main 5768494d8ae3 cached
524 files
1.8 MB
475.5k tokens
683 symbols
1 requests
Download .txt
Showing preview only (1,983K chars total). Download the full file or copy to clipboard to get everything.
Repository: MatsuriDayo/NekoBoxForAndroid
Branch: main
Commit: 5768494d8ae3
Files: 524
Total size: 1.8 MB

Directory structure:
gitextract_rsn9ha2i/

├── .github/
│   ├── ISSUE_TEMPLATE/
│   │   ├── bug-report-en.md
│   │   ├── bug-report-zh_cn.md
│   │   ├── feature_request-en.md
│   │   └── feature_request-zh_cn.md
│   └── workflows/
│       ├── preview.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
│   │   │   └── 6.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
│           │   ├── proxy_packagename.txt
│           │   └── yacd.version.txt
│           ├── java/
│           │   ├── com/
│           │   │   └── github/
│           │   │       └── shadowsocks/
│           │   │           └── plugin/
│           │   │               ├── Utils.kt
│           │   │               └── fragment/
│           │   │                   └── AlertDialogFragment.kt
│           │   ├── 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
│           │   │           │   ├── GroupFragment.kt
│           │   │           │   ├── GroupSettingsActivity.kt
│           │   │           │   ├── LogcatFragment.kt
│           │   │           │   ├── MainActivity.kt
│           │   │           │   ├── NamedFragment.kt
│           │   │           │   ├── NetworkFragment.kt
│           │   │           │   ├── ProfileSelectActivity.kt
│           │   │           │   ├── QuickDisableShortcut.kt
│           │   │           │   ├── QuickEnableShortcut.kt
│           │   │           │   ├── RouteFragment.kt
│           │   │           │   ├── RouteSettingsActivity.kt
│           │   │           │   ├── ScannerActivity.kt
│           │   │           │   ├── SettingsFragment.kt
│           │   │           │   ├── SettingsPreferenceFragment.kt
│           │   │           │   ├── StunActivity.kt
│           │   │           │   ├── SwitchActivity.kt
│           │   │           │   ├── ThemedActivity.kt
│           │   │           │   ├── ToolbarFragment.kt
│           │   │           │   ├── ToolsFragment.kt
│           │   │           │   ├── VpnRequestActivity.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/
│           │   │           │   ├── Commandline.kt
│           │   │           │   ├── CrashHandler.kt
│           │   │           │   ├── DefaultNetworkListener.kt
│           │   │           │   ├── PackageCache.kt
│           │   │           │   ├── Subnet.kt
│           │   │           │   └── Theme.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
│           │               │   ├── ConnectionTestNotification.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/
│               │   ├── 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_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
│               ├── drawable-v26/
│               │   ├── ic_qu_camera_launcher.xml
│               │   └── ic_qu_shadowsocks_launcher.xml
│               ├── layout/
│               │   ├── item_keyboard_key.xml
│               │   ├── layout_about.xml
│               │   ├── layout_add_entity.xml
│               │   ├── layout_app_list.xml
│               │   ├── layout_app_placeholder.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_webview.xml
│               │   └── simple_menu_dropdown_item.xml
│               ├── menu/
│               │   ├── add_group_menu.xml
│               │   ├── add_profile_menu.xml
│               │   ├── add_route_menu.xml
│               │   ├── app_list_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
│               ├── raw/
│               │   ├── insecure.txt
│               │   ├── not_encrypted.txt
│               │   ├── shadowsocks_stream_cipher.txt
│               │   └── vmess_md5_auth.txt
│               ├── raw-zh-rCN/
│               │   ├── insecure.txt
│               │   ├── not_encrypted.txt
│               │   ├── shadowsocks_stream_cipher.txt
│               │   └── vmess_md5_auth.txt
│               ├── resources.properties
│               ├── values/
│               │   ├── arrays.xml
│               │   ├── attrs.xml
│               │   ├── colors.xml
│               │   ├── dimens.xml
│               │   ├── ic_launcher_background.xml
│               │   ├── strings.xml
│               │   └── themes.xml
│               ├── 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
│               └── 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
│                   └── 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/
│       │   ├── build.sh
│       │   ├── get_source.sh
│       │   ├── get_source_env.sh
│       │   └── init.sh
│       └── core.sh
├── buildSrc/
│   ├── build.gradle.kts
│   └── src/
│       └── main/
│           └── kotlin/
│               └── Helpers.kt
├── gradle/
│   └── wrapper/
│       ├── gradle-wrapper.jar
│       └── gradle-wrapper.properties
├── gradle.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_android.go
│   ├── dns_box.go
│   ├── ech/
│   │   └── ech.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/
│   │   ├── 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
│   └── stun.go
├── lint.xml
├── nb4a.properties
├── release.keystore
├── repositories.gradle.kts
├── run
└── settings.gradle.kts

================================================
FILE CONTENTS
================================================

================================================
FILE: .github/ISSUE_TEMPLATE/bug-report-en.md
================================================
---
name: 'Bug Report'
about: 'Please troubleshoot server-side issues and upgrade to the latest client before raising a question.'
title: 'BUG: '
labels: ''
assignees: ''

---

## Describe the problem

Expected behavior:

Actual behavior:

## How to reproduce

Provide helpful screenshots, videos, text descriptions, subscription links, etc.

## log

If you have logs, please upload them. Please see the detailed steps for exporting logs in the documentation.

================================================
FILE: .github/ISSUE_TEMPLATE/bug-report-zh_cn.md
================================================
---
name: '问题反馈'
about: '在提出问题前请先自行排除服务器端问题和升级到最新客户端。'
title: 'BUG: '
labels: ''
assignees: ''

---

## 描述问题

预期行为:

实际行为:

## 如何复现

提供有帮助的截图,录像,文字说明,订阅链接等。

## 日志

如果有日志,请上传。请在文档内查看导出日志的详细步骤。


================================================
FILE: .github/ISSUE_TEMPLATE/feature_request-en.md
================================================
---
name: 'Feature Request'
about: 'Make suggestions for new features of the software'
title: ''
labels: ''
assignees: ''

---

## Description suggestions

## Necessity of recommendations


================================================
FILE: .github/ISSUE_TEMPLATE/feature_request-zh_cn.md
================================================
---
name: '功能请求'
about: '对软件的新功能提出建议。'
title: ''
labels: ''
assignees: ''

---

## 描述建议

## 建议的必要性


================================================
FILE: .github/workflows/preview.yml
================================================
name: Preview Build
on:
  workflow_dispatch:
    inputs:
jobs:
  libcore:
    name: Native Build (LibCore)
    runs-on: ubuntu-latest
    steps:
      - name: Checkout
        uses: actions/checkout@v4
      - name: Golang Status
        run: find buildScript libcore/*.sh | xargs cat | sha1sum > golang_status
      - name: Libcore Status
        run: git ls-files libcore | xargs cat | sha1sum > libcore_status
      - name: LibCore Cache
        id: cache
        uses: actions/cache@v4
        with:
          path: |
            app/libs/libcore.aar
          key: ${{ hashFiles('.github/workflows/*', 'golang_status', 'libcore_status') }}
      - name: Install Golang
        if: steps.cache.outputs.cache-hit != 'true'
        uses: actions/setup-go@v5
        with:
          go-version: ^1.25
      - name: Native Build
        if: steps.cache.outputs.cache-hit != 'true'
        run: ./run lib core
  build:
    name: Build OSS APK
    runs-on: ubuntu-latest
    needs:
      - libcore
    steps:
      - name: Checkout
        uses: actions/checkout@v4
      - name: Golang Status
        run: find buildScript libcore/*.sh | xargs cat | sha1sum > golang_status
      - name: Libcore Status
        run: git ls-files libcore | xargs cat | sha1sum > libcore_status
      - name: LibCore Cache
        uses: actions/cache@v4
        with:
          path: |
            app/libs/libcore.aar
          key: ${{ hashFiles('.github/workflows/*', 'golang_status', 'libcore_status') }}
      - name: Gradle cache
        uses: actions/cache@v4
        with:
          path: ~/.gradle
          key: gradle-oss-${{ hashFiles('**/*.gradle.kts') }}
      - name: Gradle Build
        env:
          BUILD_PLUGIN: none
        run: |
          echo "sdk.dir=${ANDROID_HOME}" > local.properties
          echo "ndk.dir=${ANDROID_HOME}/ndk/25.0.8775105" >> local.properties
          export LOCAL_PROPERTIES="${{ secrets.LOCAL_PROPERTIES }}"
          ./run init action gradle
          ./gradlew app:assemblePreviewRelease
          APK=$(find app/build/outputs/apk -name '*arm64-v8a*.apk')
          APK=$(dirname $APK)
          echo "APK=$APK" >> $GITHUB_ENV
      - uses: actions/upload-artifact@v4
        with:
          name: APKs
          path: ${{ env.APK }}


================================================
FILE: .github/workflows/release.yml
================================================
name: Release Build
on:
  workflow_dispatch:
    inputs:
      tag:
        description: "Release Tag"
        required: true
      publish:
        description: "Publish: If want ignore"
        required: false
      play:
        description: "Play: If want ignore"
        required: false
jobs:
  libcore:
    name: Native Build (LibCore)
    runs-on: ubuntu-latest
    steps:
      - name: Checkout
        uses: actions/checkout@v4
      - name: Golang Status
        run: find buildScript libcore/*.sh | xargs cat | sha1sum > golang_status
      - name: Libcore Status
        run: git ls-files libcore | xargs cat | sha1sum > libcore_status
      - name: LibCore Cache
        id: cache
        uses: actions/cache@v4
        with:
          path: |
            app/libs/libcore.aar
          key: ${{ hashFiles('.github/workflows/*', 'golang_status', 'libcore_status') }}
      - name: Install Golang
        if: steps.cache.outputs.cache-hit != 'true'
        uses: actions/setup-go@v5
        with:
          go-version: ^1.25
      - name: Native Build
        if: steps.cache.outputs.cache-hit != 'true'
        run: ./run lib core
  build:
    name: Build OSS APK
    runs-on: ubuntu-latest
    needs:
      - libcore
    steps:
      - name: Checkout
        uses: actions/checkout@v4
      - name: Golang Status
        run: find buildScript libcore/*.sh | xargs cat | sha1sum > golang_status
      - name: Libcore Status
        run: git ls-files libcore | xargs cat | sha1sum > libcore_status
      - name: LibCore Cache
        uses: actions/cache@v4
        with:
          path: |
            app/libs/libcore.aar
          key: ${{ hashFiles('.github/workflows/*', 'golang_status', 'libcore_status') }}
      - name: Gradle cache
        uses: actions/cache@v4
        with:
          path: ~/.gradle
          key: gradle-oss-${{ hashFiles('**/*.gradle.kts') }}
      - name: Gradle Build
        env:
          BUILD_PLUGIN: none
        run: |
          echo "sdk.dir=${ANDROID_HOME}" > local.properties
          echo "ndk.dir=${ANDROID_HOME}/ndk/25.0.8775105" >> local.properties
          export LOCAL_PROPERTIES="${{ secrets.LOCAL_PROPERTIES }}"
          ./run init action gradle
          ./gradlew app:assembleOssRelease
          APK=$(find app/build/outputs/apk -name '*arm64-v8a*.apk')
          APK=$(dirname $APK)
          echo "APK=$APK" >> $GITHUB_ENV
      - uses: actions/upload-artifact@v4
        with:
          name: APKs
          path: ${{ env.APK }}
  publish:
    name: Publish Release
    if: github.event.inputs.publish != 'y'
    runs-on: ubuntu-latest
    needs: build
    steps:
      - name: Checkout
        uses: actions/checkout@v4
      - name: Donwload Artifacts
        uses: actions/download-artifact@v4
        with:
          name: APKs
          path: artifacts
      - name: Release
        run: |
          wget -O ghr.tar.gz https://github.com/tcnksm/ghr/releases/download/v0.13.0/ghr_v0.13.0_linux_amd64.tar.gz
          tar -xvf ghr.tar.gz
          mv ghr*linux_amd64/ghr .
          mkdir apks
          find artifacts -name "*.apk" -exec cp {} apks \;
          ./ghr -delete -t "${{ github.token }}" -n "${{ github.event.inputs.tag }}" "${{ github.event.inputs.tag }}" apks
  play:
    name: Build Play Bundle
    if: github.event.inputs.play != 'y'
    runs-on: ubuntu-latest
    needs:
      - libcore
    steps:
      - name: Checkout
        uses: actions/checkout@v4
      - name: Golang Status
        run: find buildScript libcore/*.sh | xargs cat | sha1sum > golang_status
      - name: Libcore Status
        run: git ls-files libcore | xargs cat | sha1sum > libcore_status
      - name: LibCore Cache
        uses: actions/cache@v4
        with:
          path: |
            app/libs/libcore.aar
          key: ${{ hashFiles('.github/workflows/*', 'golang_status', 'libcore_status') }}
      - name: Gradle cache
        uses: actions/cache@v4
        with:
          path: ~/.gradle
          key: gradle-play-${{ hashFiles('**/*.gradle.kts') }}
      - name: Checkout Library
        run: |
          git submodule update --init 'app/*'
      - name: Gradle Build
        run: |
          echo "sdk.dir=${ANDROID_HOME}" > local.properties
          echo "ndk.dir=${ANDROID_HOME}/ndk/25.0.8775105" >> local.properties
          export LOCAL_PROPERTIES="${{ secrets.LOCAL_PROPERTIES }}"
          ./run init action gradle
          ./gradlew bundlePlayRelease
      - uses: actions/upload-artifact@v3
        with:
          name: AAB
          path: app/build/outputs/bundle/playRelease/app-play-release.aab


================================================
FILE: .gitignore
================================================
*.iml
.gradle
.idea
.vscode
.DS_Store
build/
/captures
.externalNativeBuild
.cxx
local.properties
/app/libs/
/app/src/main/assets/sing-box
/service_account_credentials.json
jniLibs/
/library/libcore_build/
.idea/deploymentTargetDropDown.xml
/nkmr

# submodules
/external


================================================
FILE: AUTHORS
================================================
SagerNet was originally created in late 2021, by
nekohasekai <contact-sagernet@sekai.icu>.

Here is an inevitably incomplete list of MUCH-APPRECIATED CONTRIBUTORS --
people who have submitted patches, fixed bugs, added translations, and
generally made SagerNet that much better:

https://github.com/SagerNet/SagerNet/graphs/contributors


================================================
FILE: LICENSE
================================================
Copyright (C) 2021 by nekohasekai <contact-sagernet@sekai.icu>

This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.

================================================
FILE: README.md
================================================
# NekoBox for Android

[![API](https://img.shields.io/badge/API-21%2B-brightgreen.svg?style=flat)](https://android-arsenal.com/api?level=21)
[![Releases](https://img.shields.io/github/v/release/MatsuriDayo/NekoBoxForAndroid)](https://github.com/MatsuriDayo/NekoBoxForAndroid/releases)
[![License: GPL-3.0](https://img.shields.io/badge/license-GPL--3.0-orange.svg)](https://www.gnu.org/licenses/gpl-3.0)

sing-box / universal proxy toolchain for Android.

一款使用 sing-box 的 Android 通用代理软件.

## 下载 / Downloads

[![GitHub All Releases](https://img.shields.io/github/downloads/Matsuridayo/NekoBoxForAndroid/total?label=downloads-total&logo=github&style=flat-square)](https://github.com/Matsuridayo/NekoBoxForAndroid/releases)

[GitHub Releases 下载](https://github.com/Matsuridayo/NekoBoxForAndroid/releases)

**Google Play 版本自 2024 年 5 月起已被第三方控制,为非开源版本,请不要下载。**

**The Google Play version has been controlled by a third party since May 2024 and is a non-open
source version. Please do not download it.**

## 更新日志 & Telegram 发布频道 / Changelog & Telegram Channel

https://t.me/Matsuridayo

## 项目主页 & 文档 / Homepage & Documents

https://matsuridayo.github.io

## 支持的代理协议 / Supported Proxy Protocols

* SOCKS (4/4a/5)
* HTTP(S)
* SSH
* Shadowsocks
* VMess
* Trojan
* VLESS
* AnyTLS
* ShadowTLS
* TUIC
* Hysteria 1/2
* WireGuard
* Trojan-Go (trojan-go-plugin)
* NaïveProxy (naive-plugin)
* Mieru (mieru-plugin)

请到[这里](https://matsuridayo.github.io/nb4a-plugin/)下载插件以获得完整的代理支持.

Please visit [here](https://matsuridayo.github.io/nb4a-plugin/) to download plugins for full proxy
supports.

## 支持的订阅格式 / Supported Subscription Format

* 一些广泛使用的格式 (如 Shadowsocks, ClashMeta 和 v2rayN)
* sing-box 出站

仅支持解析出站,即节点。分流规则等信息会被忽略。

* Some widely used formats (like Shadowsocks, ClashMeta and v2rayN)
* sing-box outbound

Only resolving outbound, i.e. nodes, is supported. Information such as diversion rules are ignored.

## 捐助 / Donate

<details>

如果这个项目对您有帮助, 可以通过捐赠的方式帮助我们维持这个项目.

捐赠满等额 50 USD 可以在「[捐赠榜](https://mtrdnt.pages.dev/donation_list)」显示头像, 如果您未被添加到这里,
欢迎联系我们补充.

Donations of 50 USD or more can display your avatar on
the [Donation List](https://mtrdnt.pages.dev/donation_list). If you are not added here, please
contact us to add it.

USDT TRC20

`TRhnA7SXE5Sap5gSG3ijxRmdYFiD4KRhPs`

XMR

`49bwESYQjoRL3xmvTcjZKHEKaiGywjLYVQJMUv79bXonGiyDCs8AzE3KiGW2ytTybBCpWJUvov8SjZZEGg66a4e59GXa6k5`

</details>

## Credits

Core:

- [SagerNet/sing-box](https://github.com/SagerNet/sing-box)

Android GUI:

- [shadowsocks/shadowsocks-android](https://github.com/shadowsocks/shadowsocks-android)
- [SagerNet/SagerNet](https://github.com/SagerNet/SagerNet)

Web Dashboard:

- [Yacd-meta](https://github.com/MetaCubeX/Yacd-meta)


================================================
FILE: app/.gitignore
================================================
/build


================================================
FILE: app/build.gradle.kts
================================================
@file:Suppress("UnstableApiUsage")

plugins {
    id("com.android.application")
    id("kotlin-android")
    id("com.google.devtools.ksp")
    id("kotlin-parcelize")
}

setupApp()

android {
    compileOptions {
        isCoreLibraryDesugaringEnabled = true
    }
    ksp {
        arg("room.incremental", "true")
        arg("room.schemaLocation", "$projectDir/schemas")
    }
    bundle {
        language {
            enableSplit = false
        }
    }
    buildFeatures {
        buildConfig = true
        viewBinding = true
        aidl = true
    }
    namespace = "io.nekohasekai.sagernet"
    packaging {
        jniLibs {
            useLegacyPackaging = true
        }
    }
    androidResources {
        generateLocaleConfig = true
    }
}

dependencies {

    implementation(fileTree("libs"))

    implementation("org.jetbrains.kotlinx:kotlinx-coroutines-android:1.6.4")
    implementation("androidx.core:core-ktx:1.9.0")
    implementation("androidx.recyclerview:recyclerview:1.3.0")
    implementation("androidx.activity:activity-ktx:1.10.1")
    implementation("androidx.fragment:fragment-ktx:1.5.6")
    implementation("androidx.browser:browser:1.5.0")
    implementation("androidx.swiperefreshlayout:swiperefreshlayout:1.1.0")
    implementation("androidx.constraintlayout:constraintlayout:2.1.4")
    implementation("androidx.navigation:navigation-fragment-ktx:2.5.3")
    implementation("androidx.navigation:navigation-ui-ktx:2.5.3")
    implementation("androidx.preference:preference-ktx:1.2.0")
    implementation("androidx.appcompat:appcompat:1.6.1")
    implementation("androidx.work:work-runtime-ktx:2.8.1")
    implementation("androidx.work:work-multiprocess:2.8.1")

    implementation("com.google.android.material:material:1.8.0")
    implementation("com.google.code.gson:gson:2.9.0")

    implementation("com.github.jenly1314:zxing-lite:2.1.1")
    implementation("com.blacksquircle.ui:editorkit:2.6.0")
    implementation("com.blacksquircle.ui:language-base:2.6.0")
    implementation("com.blacksquircle.ui:language-json:2.6.0")

    implementation("com.squareup.okhttp3:okhttp:5.0.0-alpha.3")
    implementation("org.yaml:snakeyaml:1.30")
    implementation("com.github.daniel-stoneuk:material-about-library:3.2.0-rc01")
    implementation("com.jakewharton:process-phoenix:2.1.2")
    implementation("com.esotericsoftware:kryo:5.2.1")
    implementation("com.google.guava:guava:31.0.1-android")
    implementation("org.ini4j:ini4j:0.5.4")

    implementation("com.simplecityapps:recyclerview-fastscroll:2.0.1") {
        exclude(group = "androidx.recyclerview")
        exclude(group = "androidx.appcompat")
    }

    implementation("androidx.room:room-runtime:2.6.1")
    ksp("androidx.room:room-compiler:2.6.1")
    implementation("androidx.room:room-ktx:2.6.1")
    implementation("com.github.MatrixDev.Roomigrant:RoomigrantLib:0.3.4")
    ksp("com.github.MatrixDev.Roomigrant:RoomigrantCompiler:0.3.4")

    coreLibraryDesugaring("com.android.tools:desugar_jdk_libs:2.0.3")
}


================================================
FILE: app/executableSo/.gitignore
================================================
*.so


================================================
FILE: app/proguard-rules.pro
================================================
-repackageclasses ''
-allowaccessmodification

-keep class io.nekohasekai.sagernet.** { *;}
-keep class moe.matsuri.nb4a.** { *;}

# Clean Kotlin
-assumenosideeffects class kotlin.jvm.internal.Intrinsics {
    static void checkParameterIsNotNull(java.lang.Object, java.lang.String);
    static void checkExpressionValueIsNotNull(java.lang.Object, java.lang.String);
    static void checkNotNullExpressionValue(java.lang.Object, java.lang.String);
    static void checkReturnedValueIsNotNull(java.lang.Object, java.lang.String, java.lang.String);
    static void checkReturnedValueIsNotNull(java.lang.Object, java.lang.String);
    static void checkFieldIsNotNull(java.lang.Object, java.lang.String, java.lang.String);
    static void checkFieldIsNotNull(java.lang.Object, java.lang.String);
    static void checkNotNull(java.lang.Object);
    static void checkNotNull(java.lang.Object, java.lang.String);
    static void checkNotNullParameter(java.lang.Object, java.lang.String);
    static void throwUninitializedPropertyAccessException(java.lang.String);
}

# ini4j
-keep public class org.ini4j.spi.** { <init>(); }

# SnakeYaml
-keep class org.yaml.snakeyaml.** { *; }

-dontobfuscate
-keepattributes SourceFile

-dontwarn java.beans.BeanInfo
-dontwarn java.beans.FeatureDescriptor
-dontwarn java.beans.IntrospectionException
-dontwarn java.beans.Introspector
-dontwarn java.beans.PropertyDescriptor
-dontwarn java.beans.Transient
-dontwarn java.beans.VetoableChangeListener
-dontwarn java.beans.VetoableChangeSupport
-dontwarn org.apache.harmony.xnet.provider.jsse.SSLParametersImpl
-dontwarn org.bouncycastle.jce.provider.BouncyCastleProvider
-dontwarn org.bouncycastle.jsse.BCSSLParameters
-dontwarn org.bouncycastle.jsse.BCSSLSocket
-dontwarn org.bouncycastle.jsse.provider.BouncyCastleJsseProvider
-dontwarn org.openjsse.javax.net.ssl.SSLParameters
-dontwarn org.openjsse.javax.net.ssl.SSLSocket
-dontwarn org.openjsse.net.ssl.OpenJSSE
-dontwarn java.beans.PropertyVetoException


================================================
FILE: app/schemas/io.nekohasekai.sagernet.database.SagerDatabase/1.json
================================================
{
  "formatVersion": 1,
  "database": {
    "version": 1,
    "identityHash": "f66fd943df1d9e86d281a2e32c9fdd47",
    "entities": [
      {
        "tableName": "proxy_groups",
        "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `userOrder` INTEGER NOT NULL, `ungrouped` INTEGER NOT NULL, `name` TEXT, `type` INTEGER NOT NULL, `subscription` BLOB, `order` INTEGER NOT NULL)",
        "fields": [
          {
            "fieldPath": "id",
            "columnName": "id",
            "affinity": "INTEGER",
            "notNull": true
          },
          {
            "fieldPath": "userOrder",
            "columnName": "userOrder",
            "affinity": "INTEGER",
            "notNull": true
          },
          {
            "fieldPath": "ungrouped",
            "columnName": "ungrouped",
            "affinity": "INTEGER",
            "notNull": true
          },
          {
            "fieldPath": "name",
            "columnName": "name",
            "affinity": "TEXT",
            "notNull": false
          },
          {
            "fieldPath": "type",
            "columnName": "type",
            "affinity": "INTEGER",
            "notNull": true
          },
          {
            "fieldPath": "subscription",
            "columnName": "subscription",
            "affinity": "BLOB",
            "notNull": false
          },
          {
            "fieldPath": "order",
            "columnName": "order",
            "affinity": "INTEGER",
            "notNull": true
          }
        ],
        "primaryKey": {
          "columnNames": [
            "id"
          ],
          "autoGenerate": true
        },
        "indices": [],
        "foreignKeys": []
      },
      {
        "tableName": "proxy_entities",
        "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `groupId` INTEGER NOT NULL, `type` INTEGER NOT NULL, `userOrder` INTEGER NOT NULL, `tx` INTEGER NOT NULL, `rx` INTEGER NOT NULL, `status` INTEGER NOT NULL, `ping` INTEGER NOT NULL, `uuid` TEXT NOT NULL, `error` TEXT, `socksBean` BLOB, `httpBean` BLOB, `ssBean` BLOB, `vmessBean` BLOB, `trojanBean` BLOB, `trojanGoBean` BLOB, `naiveBean` BLOB, `hysteriaBean` BLOB, `tuicBean` BLOB, `sshBean` BLOB, `wgBean` BLOB, `chainBean` BLOB, `nekoBean` BLOB, `configBean` BLOB)",
        "fields": [
          {
            "fieldPath": "id",
            "columnName": "id",
            "affinity": "INTEGER",
            "notNull": true
          },
          {
            "fieldPath": "groupId",
            "columnName": "groupId",
            "affinity": "INTEGER",
            "notNull": true
          },
          {
            "fieldPath": "type",
            "columnName": "type",
            "affinity": "INTEGER",
            "notNull": true
          },
          {
            "fieldPath": "userOrder",
            "columnName": "userOrder",
            "affinity": "INTEGER",
            "notNull": true
          },
          {
            "fieldPath": "tx",
            "columnName": "tx",
            "affinity": "INTEGER",
            "notNull": true
          },
          {
            "fieldPath": "rx",
            "columnName": "rx",
            "affinity": "INTEGER",
            "notNull": true
          },
          {
            "fieldPath": "status",
            "columnName": "status",
            "affinity": "INTEGER",
            "notNull": true
          },
          {
            "fieldPath": "ping",
            "columnName": "ping",
            "affinity": "INTEGER",
            "notNull": true
          },
          {
            "fieldPath": "uuid",
            "columnName": "uuid",
            "affinity": "TEXT",
            "notNull": true
          },
          {
            "fieldPath": "error",
            "columnName": "error",
            "affinity": "TEXT",
            "notNull": false
          },
          {
            "fieldPath": "socksBean",
            "columnName": "socksBean",
            "affinity": "BLOB",
            "notNull": false
          },
          {
            "fieldPath": "httpBean",
            "columnName": "httpBean",
            "affinity": "BLOB",
            "notNull": false
          },
          {
            "fieldPath": "ssBean",
            "columnName": "ssBean",
            "affinity": "BLOB",
            "notNull": false
          },
          {
            "fieldPath": "vmessBean",
            "columnName": "vmessBean",
            "affinity": "BLOB",
            "notNull": false
          },
          {
            "fieldPath": "trojanBean",
            "columnName": "trojanBean",
            "affinity": "BLOB",
            "notNull": false
          },
          {
            "fieldPath": "trojanGoBean",
            "columnName": "trojanGoBean",
            "affinity": "BLOB",
            "notNull": false
          },
          {
            "fieldPath": "naiveBean",
            "columnName": "naiveBean",
            "affinity": "BLOB",
            "notNull": false
          },
          {
            "fieldPath": "hysteriaBean",
            "columnName": "hysteriaBean",
            "affinity": "BLOB",
            "notNull": false
          },
          {
            "fieldPath": "tuicBean",
            "columnName": "tuicBean",
            "affinity": "BLOB",
            "notNull": false
          },
          {
            "fieldPath": "sshBean",
            "columnName": "sshBean",
            "affinity": "BLOB",
            "notNull": false
          },
          {
            "fieldPath": "wgBean",
            "columnName": "wgBean",
            "affinity": "BLOB",
            "notNull": false
          },
          {
            "fieldPath": "chainBean",
            "columnName": "chainBean",
            "affinity": "BLOB",
            "notNull": false
          },
          {
            "fieldPath": "nekoBean",
            "columnName": "nekoBean",
            "affinity": "BLOB",
            "notNull": false
          },
          {
            "fieldPath": "configBean",
            "columnName": "configBean",
            "affinity": "BLOB",
            "notNull": false
          }
        ],
        "primaryKey": {
          "columnNames": [
            "id"
          ],
          "autoGenerate": true
        },
        "indices": [
          {
            "name": "groupId",
            "unique": false,
            "columnNames": [
              "groupId"
            ],
            "orders": [],
            "createSql": "CREATE INDEX IF NOT EXISTS `groupId` ON `${TABLE_NAME}` (`groupId`)"
          }
        ],
        "foreignKeys": []
      },
      {
        "tableName": "rules",
        "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `name` TEXT NOT NULL, `userOrder` INTEGER NOT NULL, `enabled` INTEGER NOT NULL, `domains` TEXT NOT NULL, `ip` TEXT NOT NULL, `port` TEXT NOT NULL, `sourcePort` TEXT NOT NULL, `network` TEXT NOT NULL, `source` TEXT NOT NULL, `protocol` TEXT NOT NULL, `outbound` INTEGER NOT NULL, `packages` TEXT NOT NULL)",
        "fields": [
          {
            "fieldPath": "id",
            "columnName": "id",
            "affinity": "INTEGER",
            "notNull": true
          },
          {
            "fieldPath": "name",
            "columnName": "name",
            "affinity": "TEXT",
            "notNull": true
          },
          {
            "fieldPath": "userOrder",
            "columnName": "userOrder",
            "affinity": "INTEGER",
            "notNull": true
          },
          {
            "fieldPath": "enabled",
            "columnName": "enabled",
            "affinity": "INTEGER",
            "notNull": true
          },
          {
            "fieldPath": "domains",
            "columnName": "domains",
            "affinity": "TEXT",
            "notNull": true
          },
          {
            "fieldPath": "ip",
            "columnName": "ip",
            "affinity": "TEXT",
            "notNull": true
          },
          {
            "fieldPath": "port",
            "columnName": "port",
            "affinity": "TEXT",
            "notNull": true
          },
          {
            "fieldPath": "sourcePort",
            "columnName": "sourcePort",
            "affinity": "TEXT",
            "notNull": true
          },
          {
            "fieldPath": "network",
            "columnName": "network",
            "affinity": "TEXT",
            "notNull": true
          },
          {
            "fieldPath": "source",
            "columnName": "source",
            "affinity": "TEXT",
            "notNull": true
          },
          {
            "fieldPath": "protocol",
            "columnName": "protocol",
            "affinity": "TEXT",
            "notNull": true
          },
          {
            "fieldPath": "outbound",
            "columnName": "outbound",
            "affinity": "INTEGER",
            "notNull": true
          },
          {
            "fieldPath": "packages",
            "columnName": "packages",
            "affinity": "TEXT",
            "notNull": true
          }
        ],
        "primaryKey": {
          "columnNames": [
            "id"
          ],
          "autoGenerate": true
        },
        "indices": [],
        "foreignKeys": []
      }
    ],
    "views": [],
    "setupQueries": [
      "CREATE TABLE IF NOT EXISTS room_master_table (id INTEGER PRIMARY KEY,identity_hash TEXT)",
      "INSERT OR REPLACE INTO room_master_table (id,identity_hash) VALUES(42, 'f66fd943df1d9e86d281a2e32c9fdd47')"
    ]
  }
}

================================================
FILE: app/schemas/io.nekohasekai.sagernet.database.SagerDatabase/2.json
================================================
{
  "formatVersion": 1,
  "database": {
    "version": 2,
    "identityHash": "9ec160533656482a17cbd563e9e3e416",
    "entities": [
      {
        "tableName": "proxy_groups",
        "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `userOrder` INTEGER NOT NULL, `ungrouped` INTEGER NOT NULL, `name` TEXT, `type` INTEGER NOT NULL, `subscription` BLOB, `order` INTEGER NOT NULL, `isSelector` INTEGER NOT NULL, `frontProxy` INTEGER NOT NULL, `landingProxy` INTEGER NOT NULL)",
        "fields": [
          {
            "fieldPath": "id",
            "columnName": "id",
            "affinity": "INTEGER",
            "notNull": true
          },
          {
            "fieldPath": "userOrder",
            "columnName": "userOrder",
            "affinity": "INTEGER",
            "notNull": true
          },
          {
            "fieldPath": "ungrouped",
            "columnName": "ungrouped",
            "affinity": "INTEGER",
            "notNull": true
          },
          {
            "fieldPath": "name",
            "columnName": "name",
            "affinity": "TEXT",
            "notNull": false
          },
          {
            "fieldPath": "type",
            "columnName": "type",
            "affinity": "INTEGER",
            "notNull": true
          },
          {
            "fieldPath": "subscription",
            "columnName": "subscription",
            "affinity": "BLOB",
            "notNull": false
          },
          {
            "fieldPath": "order",
            "columnName": "order",
            "affinity": "INTEGER",
            "notNull": true
          },
          {
            "fieldPath": "isSelector",
            "columnName": "isSelector",
            "affinity": "INTEGER",
            "notNull": true
          },
          {
            "fieldPath": "frontProxy",
            "columnName": "frontProxy",
            "affinity": "INTEGER",
            "notNull": true
          },
          {
            "fieldPath": "landingProxy",
            "columnName": "landingProxy",
            "affinity": "INTEGER",
            "notNull": true
          }
        ],
        "primaryKey": {
          "autoGenerate": true,
          "columnNames": [
            "id"
          ]
        },
        "indices": [],
        "foreignKeys": []
      },
      {
        "tableName": "proxy_entities",
        "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `groupId` INTEGER NOT NULL, `type` INTEGER NOT NULL, `userOrder` INTEGER NOT NULL, `tx` INTEGER NOT NULL, `rx` INTEGER NOT NULL, `status` INTEGER NOT NULL, `ping` INTEGER NOT NULL, `uuid` TEXT NOT NULL, `error` TEXT, `socksBean` BLOB, `httpBean` BLOB, `ssBean` BLOB, `vmessBean` BLOB, `trojanBean` BLOB, `trojanGoBean` BLOB, `naiveBean` BLOB, `hysteriaBean` BLOB, `tuicBean` BLOB, `sshBean` BLOB, `wgBean` BLOB, `shadowTLSBean` BLOB, `chainBean` BLOB, `nekoBean` BLOB, `configBean` BLOB)",
        "fields": [
          {
            "fieldPath": "id",
            "columnName": "id",
            "affinity": "INTEGER",
            "notNull": true
          },
          {
            "fieldPath": "groupId",
            "columnName": "groupId",
            "affinity": "INTEGER",
            "notNull": true
          },
          {
            "fieldPath": "type",
            "columnName": "type",
            "affinity": "INTEGER",
            "notNull": true
          },
          {
            "fieldPath": "userOrder",
            "columnName": "userOrder",
            "affinity": "INTEGER",
            "notNull": true
          },
          {
            "fieldPath": "tx",
            "columnName": "tx",
            "affinity": "INTEGER",
            "notNull": true
          },
          {
            "fieldPath": "rx",
            "columnName": "rx",
            "affinity": "INTEGER",
            "notNull": true
          },
          {
            "fieldPath": "status",
            "columnName": "status",
            "affinity": "INTEGER",
            "notNull": true
          },
          {
            "fieldPath": "ping",
            "columnName": "ping",
            "affinity": "INTEGER",
            "notNull": true
          },
          {
            "fieldPath": "uuid",
            "columnName": "uuid",
            "affinity": "TEXT",
            "notNull": true
          },
          {
            "fieldPath": "error",
            "columnName": "error",
            "affinity": "TEXT",
            "notNull": false
          },
          {
            "fieldPath": "socksBean",
            "columnName": "socksBean",
            "affinity": "BLOB",
            "notNull": false
          },
          {
            "fieldPath": "httpBean",
            "columnName": "httpBean",
            "affinity": "BLOB",
            "notNull": false
          },
          {
            "fieldPath": "ssBean",
            "columnName": "ssBean",
            "affinity": "BLOB",
            "notNull": false
          },
          {
            "fieldPath": "vmessBean",
            "columnName": "vmessBean",
            "affinity": "BLOB",
            "notNull": false
          },
          {
            "fieldPath": "trojanBean",
            "columnName": "trojanBean",
            "affinity": "BLOB",
            "notNull": false
          },
          {
            "fieldPath": "trojanGoBean",
            "columnName": "trojanGoBean",
            "affinity": "BLOB",
            "notNull": false
          },
          {
            "fieldPath": "naiveBean",
            "columnName": "naiveBean",
            "affinity": "BLOB",
            "notNull": false
          },
          {
            "fieldPath": "hysteriaBean",
            "columnName": "hysteriaBean",
            "affinity": "BLOB",
            "notNull": false
          },
          {
            "fieldPath": "tuicBean",
            "columnName": "tuicBean",
            "affinity": "BLOB",
            "notNull": false
          },
          {
            "fieldPath": "sshBean",
            "columnName": "sshBean",
            "affinity": "BLOB",
            "notNull": false
          },
          {
            "fieldPath": "wgBean",
            "columnName": "wgBean",
            "affinity": "BLOB",
            "notNull": false
          },
          {
            "fieldPath": "shadowTLSBean",
            "columnName": "shadowTLSBean",
            "affinity": "BLOB",
            "notNull": false
          },
          {
            "fieldPath": "chainBean",
            "columnName": "chainBean",
            "affinity": "BLOB",
            "notNull": false
          },
          {
            "fieldPath": "nekoBean",
            "columnName": "nekoBean",
            "affinity": "BLOB",
            "notNull": false
          },
          {
            "fieldPath": "configBean",
            "columnName": "configBean",
            "affinity": "BLOB",
            "notNull": false
          }
        ],
        "primaryKey": {
          "autoGenerate": true,
          "columnNames": [
            "id"
          ]
        },
        "indices": [
          {
            "name": "groupId",
            "unique": false,
            "columnNames": [
              "groupId"
            ],
            "orders": [],
            "createSql": "CREATE INDEX IF NOT EXISTS `groupId` ON `${TABLE_NAME}` (`groupId`)"
          }
        ],
        "foreignKeys": []
      },
      {
        "tableName": "rules",
        "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `name` TEXT NOT NULL, `userOrder` INTEGER NOT NULL, `enabled` INTEGER NOT NULL, `domains` TEXT NOT NULL, `ip` TEXT NOT NULL, `port` TEXT NOT NULL, `sourcePort` TEXT NOT NULL, `network` TEXT NOT NULL, `source` TEXT NOT NULL, `protocol` TEXT NOT NULL, `outbound` INTEGER NOT NULL, `packages` TEXT NOT NULL)",
        "fields": [
          {
            "fieldPath": "id",
            "columnName": "id",
            "affinity": "INTEGER",
            "notNull": true
          },
          {
            "fieldPath": "name",
            "columnName": "name",
            "affinity": "TEXT",
            "notNull": true
          },
          {
            "fieldPath": "userOrder",
            "columnName": "userOrder",
            "affinity": "INTEGER",
            "notNull": true
          },
          {
            "fieldPath": "enabled",
            "columnName": "enabled",
            "affinity": "INTEGER",
            "notNull": true
          },
          {
            "fieldPath": "domains",
            "columnName": "domains",
            "affinity": "TEXT",
            "notNull": true
          },
          {
            "fieldPath": "ip",
            "columnName": "ip",
            "affinity": "TEXT",
            "notNull": true
          },
          {
            "fieldPath": "port",
            "columnName": "port",
            "affinity": "TEXT",
            "notNull": true
          },
          {
            "fieldPath": "sourcePort",
            "columnName": "sourcePort",
            "affinity": "TEXT",
            "notNull": true
          },
          {
            "fieldPath": "network",
            "columnName": "network",
            "affinity": "TEXT",
            "notNull": true
          },
          {
            "fieldPath": "source",
            "columnName": "source",
            "affinity": "TEXT",
            "notNull": true
          },
          {
            "fieldPath": "protocol",
            "columnName": "protocol",
            "affinity": "TEXT",
            "notNull": true
          },
          {
            "fieldPath": "outbound",
            "columnName": "outbound",
            "affinity": "INTEGER",
            "notNull": true
          },
          {
            "fieldPath": "packages",
            "columnName": "packages",
            "affinity": "TEXT",
            "notNull": true
          }
        ],
        "primaryKey": {
          "autoGenerate": true,
          "columnNames": [
            "id"
          ]
        },
        "indices": [],
        "foreignKeys": []
      }
    ],
    "views": [],
    "setupQueries": [
      "CREATE TABLE IF NOT EXISTS room_master_table (id INTEGER PRIMARY KEY,identity_hash TEXT)",
      "INSERT OR REPLACE INTO room_master_table (id,identity_hash) VALUES(42, '9ec160533656482a17cbd563e9e3e416')"
    ]
  }
}

================================================
FILE: app/schemas/io.nekohasekai.sagernet.database.SagerDatabase/3.json
================================================
{
  "formatVersion": 1,
  "database": {
    "version": 3,
    "identityHash": "cff00d0142d9e53d2ca24a6a55cd213c",
    "entities": [
      {
        "tableName": "proxy_groups",
        "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `userOrder` INTEGER NOT NULL, `ungrouped` INTEGER NOT NULL, `name` TEXT, `type` INTEGER NOT NULL, `subscription` BLOB, `order` INTEGER NOT NULL, `isSelector` INTEGER NOT NULL, `frontProxy` INTEGER NOT NULL, `landingProxy` INTEGER NOT NULL)",
        "fields": [
          {
            "fieldPath": "id",
            "columnName": "id",
            "affinity": "INTEGER",
            "notNull": true
          },
          {
            "fieldPath": "userOrder",
            "columnName": "userOrder",
            "affinity": "INTEGER",
            "notNull": true
          },
          {
            "fieldPath": "ungrouped",
            "columnName": "ungrouped",
            "affinity": "INTEGER",
            "notNull": true
          },
          {
            "fieldPath": "name",
            "columnName": "name",
            "affinity": "TEXT",
            "notNull": false
          },
          {
            "fieldPath": "type",
            "columnName": "type",
            "affinity": "INTEGER",
            "notNull": true
          },
          {
            "fieldPath": "subscription",
            "columnName": "subscription",
            "affinity": "BLOB",
            "notNull": false
          },
          {
            "fieldPath": "order",
            "columnName": "order",
            "affinity": "INTEGER",
            "notNull": true
          },
          {
            "fieldPath": "isSelector",
            "columnName": "isSelector",
            "affinity": "INTEGER",
            "notNull": true
          },
          {
            "fieldPath": "frontProxy",
            "columnName": "frontProxy",
            "affinity": "INTEGER",
            "notNull": true
          },
          {
            "fieldPath": "landingProxy",
            "columnName": "landingProxy",
            "affinity": "INTEGER",
            "notNull": true
          }
        ],
        "primaryKey": {
          "autoGenerate": true,
          "columnNames": [
            "id"
          ]
        },
        "indices": [],
        "foreignKeys": []
      },
      {
        "tableName": "proxy_entities",
        "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `groupId` INTEGER NOT NULL, `type` INTEGER NOT NULL, `userOrder` INTEGER NOT NULL, `tx` INTEGER NOT NULL, `rx` INTEGER NOT NULL, `status` INTEGER NOT NULL, `ping` INTEGER NOT NULL, `uuid` TEXT NOT NULL, `error` TEXT, `socksBean` BLOB, `httpBean` BLOB, `ssBean` BLOB, `vmessBean` BLOB, `trojanBean` BLOB, `trojanGoBean` BLOB, `mieruBean` BLOB, `naiveBean` BLOB, `hysteriaBean` BLOB, `tuicBean` BLOB, `sshBean` BLOB, `wgBean` BLOB, `shadowTLSBean` BLOB, `chainBean` BLOB, `nekoBean` BLOB, `configBean` BLOB)",
        "fields": [
          {
            "fieldPath": "id",
            "columnName": "id",
            "affinity": "INTEGER",
            "notNull": true
          },
          {
            "fieldPath": "groupId",
            "columnName": "groupId",
            "affinity": "INTEGER",
            "notNull": true
          },
          {
            "fieldPath": "type",
            "columnName": "type",
            "affinity": "INTEGER",
            "notNull": true
          },
          {
            "fieldPath": "userOrder",
            "columnName": "userOrder",
            "affinity": "INTEGER",
            "notNull": true
          },
          {
            "fieldPath": "tx",
            "columnName": "tx",
            "affinity": "INTEGER",
            "notNull": true
          },
          {
            "fieldPath": "rx",
            "columnName": "rx",
            "affinity": "INTEGER",
            "notNull": true
          },
          {
            "fieldPath": "status",
            "columnName": "status",
            "affinity": "INTEGER",
            "notNull": true
          },
          {
            "fieldPath": "ping",
            "columnName": "ping",
            "affinity": "INTEGER",
            "notNull": true
          },
          {
            "fieldPath": "uuid",
            "columnName": "uuid",
            "affinity": "TEXT",
            "notNull": true
          },
          {
            "fieldPath": "error",
            "columnName": "error",
            "affinity": "TEXT",
            "notNull": false
          },
          {
            "fieldPath": "socksBean",
            "columnName": "socksBean",
            "affinity": "BLOB",
            "notNull": false
          },
          {
            "fieldPath": "httpBean",
            "columnName": "httpBean",
            "affinity": "BLOB",
            "notNull": false
          },
          {
            "fieldPath": "ssBean",
            "columnName": "ssBean",
            "affinity": "BLOB",
            "notNull": false
          },
          {
            "fieldPath": "vmessBean",
            "columnName": "vmessBean",
            "affinity": "BLOB",
            "notNull": false
          },
          {
            "fieldPath": "trojanBean",
            "columnName": "trojanBean",
            "affinity": "BLOB",
            "notNull": false
          },
          {
            "fieldPath": "trojanGoBean",
            "columnName": "trojanGoBean",
            "affinity": "BLOB",
            "notNull": false
          },
          {
            "fieldPath": "mieruBean",
            "columnName": "mieruBean",
            "affinity": "BLOB",
            "notNull": false
          },
          {
            "fieldPath": "naiveBean",
            "columnName": "naiveBean",
            "affinity": "BLOB",
            "notNull": false
          },
          {
            "fieldPath": "hysteriaBean",
            "columnName": "hysteriaBean",
            "affinity": "BLOB",
            "notNull": false
          },
          {
            "fieldPath": "tuicBean",
            "columnName": "tuicBean",
            "affinity": "BLOB",
            "notNull": false
          },
          {
            "fieldPath": "sshBean",
            "columnName": "sshBean",
            "affinity": "BLOB",
            "notNull": false
          },
          {
            "fieldPath": "wgBean",
            "columnName": "wgBean",
            "affinity": "BLOB",
            "notNull": false
          },
          {
            "fieldPath": "shadowTLSBean",
            "columnName": "shadowTLSBean",
            "affinity": "BLOB",
            "notNull": false
          },
          {
            "fieldPath": "chainBean",
            "columnName": "chainBean",
            "affinity": "BLOB",
            "notNull": false
          },
          {
            "fieldPath": "nekoBean",
            "columnName": "nekoBean",
            "affinity": "BLOB",
            "notNull": false
          },
          {
            "fieldPath": "configBean",
            "columnName": "configBean",
            "affinity": "BLOB",
            "notNull": false
          }
        ],
        "primaryKey": {
          "autoGenerate": true,
          "columnNames": [
            "id"
          ]
        },
        "indices": [
          {
            "name": "groupId",
            "unique": false,
            "columnNames": [
              "groupId"
            ],
            "orders": [],
            "createSql": "CREATE INDEX IF NOT EXISTS `groupId` ON `${TABLE_NAME}` (`groupId`)"
          }
        ],
        "foreignKeys": []
      },
      {
        "tableName": "rules",
        "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `name` TEXT NOT NULL, `userOrder` INTEGER NOT NULL, `enabled` INTEGER NOT NULL, `domains` TEXT NOT NULL, `ip` TEXT NOT NULL, `port` TEXT NOT NULL, `sourcePort` TEXT NOT NULL, `network` TEXT NOT NULL, `source` TEXT NOT NULL, `protocol` TEXT NOT NULL, `outbound` INTEGER NOT NULL, `packages` TEXT NOT NULL)",
        "fields": [
          {
            "fieldPath": "id",
            "columnName": "id",
            "affinity": "INTEGER",
            "notNull": true
          },
          {
            "fieldPath": "name",
            "columnName": "name",
            "affinity": "TEXT",
            "notNull": true
          },
          {
            "fieldPath": "userOrder",
            "columnName": "userOrder",
            "affinity": "INTEGER",
            "notNull": true
          },
          {
            "fieldPath": "enabled",
            "columnName": "enabled",
            "affinity": "INTEGER",
            "notNull": true
          },
          {
            "fieldPath": "domains",
            "columnName": "domains",
            "affinity": "TEXT",
            "notNull": true
          },
          {
            "fieldPath": "ip",
            "columnName": "ip",
            "affinity": "TEXT",
            "notNull": true
          },
          {
            "fieldPath": "port",
            "columnName": "port",
            "affinity": "TEXT",
            "notNull": true
          },
          {
            "fieldPath": "sourcePort",
            "columnName": "sourcePort",
            "affinity": "TEXT",
            "notNull": true
          },
          {
            "fieldPath": "network",
            "columnName": "network",
            "affinity": "TEXT",
            "notNull": true
          },
          {
            "fieldPath": "source",
            "columnName": "source",
            "affinity": "TEXT",
            "notNull": true
          },
          {
            "fieldPath": "protocol",
            "columnName": "protocol",
            "affinity": "TEXT",
            "notNull": true
          },
          {
            "fieldPath": "outbound",
            "columnName": "outbound",
            "affinity": "INTEGER",
            "notNull": true
          },
          {
            "fieldPath": "packages",
            "columnName": "packages",
            "affinity": "TEXT",
            "notNull": true
          }
        ],
        "primaryKey": {
          "autoGenerate": true,
          "columnNames": [
            "id"
          ]
        },
        "indices": [],
        "foreignKeys": []
      }
    ],
    "views": [],
    "setupQueries": [
      "CREATE TABLE IF NOT EXISTS room_master_table (id INTEGER PRIMARY KEY,identity_hash TEXT)",
      "INSERT OR REPLACE INTO room_master_table (id,identity_hash) VALUES(42, 'cff00d0142d9e53d2ca24a6a55cd213c')"
    ]
  }
}

================================================
FILE: app/schemas/io.nekohasekai.sagernet.database.SagerDatabase/4.json
================================================
{
  "formatVersion": 1,
  "database": {
    "version": 4,
    "identityHash": "cff00d0142d9e53d2ca24a6a55cd213c",
    "entities": [
      {
        "tableName": "proxy_groups",
        "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `userOrder` INTEGER NOT NULL, `ungrouped` INTEGER NOT NULL, `name` TEXT, `type` INTEGER NOT NULL, `subscription` BLOB, `order` INTEGER NOT NULL, `isSelector` INTEGER NOT NULL, `frontProxy` INTEGER NOT NULL, `landingProxy` INTEGER NOT NULL)",
        "fields": [
          {
            "fieldPath": "id",
            "columnName": "id",
            "affinity": "INTEGER",
            "notNull": true
          },
          {
            "fieldPath": "userOrder",
            "columnName": "userOrder",
            "affinity": "INTEGER",
            "notNull": true
          },
          {
            "fieldPath": "ungrouped",
            "columnName": "ungrouped",
            "affinity": "INTEGER",
            "notNull": true
          },
          {
            "fieldPath": "name",
            "columnName": "name",
            "affinity": "TEXT",
            "notNull": false
          },
          {
            "fieldPath": "type",
            "columnName": "type",
            "affinity": "INTEGER",
            "notNull": true
          },
          {
            "fieldPath": "subscription",
            "columnName": "subscription",
            "affinity": "BLOB",
            "notNull": false
          },
          {
            "fieldPath": "order",
            "columnName": "order",
            "affinity": "INTEGER",
            "notNull": true
          },
          {
            "fieldPath": "isSelector",
            "columnName": "isSelector",
            "affinity": "INTEGER",
            "notNull": true
          },
          {
            "fieldPath": "frontProxy",
            "columnName": "frontProxy",
            "affinity": "INTEGER",
            "notNull": true
          },
          {
            "fieldPath": "landingProxy",
            "columnName": "landingProxy",
            "affinity": "INTEGER",
            "notNull": true
          }
        ],
        "primaryKey": {
          "autoGenerate": true,
          "columnNames": [
            "id"
          ]
        },
        "indices": [],
        "foreignKeys": []
      },
      {
        "tableName": "proxy_entities",
        "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `groupId` INTEGER NOT NULL, `type` INTEGER NOT NULL, `userOrder` INTEGER NOT NULL, `tx` INTEGER NOT NULL, `rx` INTEGER NOT NULL, `status` INTEGER NOT NULL, `ping` INTEGER NOT NULL, `uuid` TEXT NOT NULL, `error` TEXT, `socksBean` BLOB, `httpBean` BLOB, `ssBean` BLOB, `vmessBean` BLOB, `trojanBean` BLOB, `trojanGoBean` BLOB, `mieruBean` BLOB, `naiveBean` BLOB, `hysteriaBean` BLOB, `tuicBean` BLOB, `sshBean` BLOB, `wgBean` BLOB, `shadowTLSBean` BLOB, `chainBean` BLOB, `nekoBean` BLOB, `configBean` BLOB)",
        "fields": [
          {
            "fieldPath": "id",
            "columnName": "id",
            "affinity": "INTEGER",
            "notNull": true
          },
          {
            "fieldPath": "groupId",
            "columnName": "groupId",
            "affinity": "INTEGER",
            "notNull": true
          },
          {
            "fieldPath": "type",
            "columnName": "type",
            "affinity": "INTEGER",
            "notNull": true
          },
          {
            "fieldPath": "userOrder",
            "columnName": "userOrder",
            "affinity": "INTEGER",
            "notNull": true
          },
          {
            "fieldPath": "tx",
            "columnName": "tx",
            "affinity": "INTEGER",
            "notNull": true
          },
          {
            "fieldPath": "rx",
            "columnName": "rx",
            "affinity": "INTEGER",
            "notNull": true
          },
          {
            "fieldPath": "status",
            "columnName": "status",
            "affinity": "INTEGER",
            "notNull": true
          },
          {
            "fieldPath": "ping",
            "columnName": "ping",
            "affinity": "INTEGER",
            "notNull": true
          },
          {
            "fieldPath": "uuid",
            "columnName": "uuid",
            "affinity": "TEXT",
            "notNull": true
          },
          {
            "fieldPath": "error",
            "columnName": "error",
            "affinity": "TEXT",
            "notNull": false
          },
          {
            "fieldPath": "socksBean",
            "columnName": "socksBean",
            "affinity": "BLOB",
            "notNull": false
          },
          {
            "fieldPath": "httpBean",
            "columnName": "httpBean",
            "affinity": "BLOB",
            "notNull": false
          },
          {
            "fieldPath": "ssBean",
            "columnName": "ssBean",
            "affinity": "BLOB",
            "notNull": false
          },
          {
            "fieldPath": "vmessBean",
            "columnName": "vmessBean",
            "affinity": "BLOB",
            "notNull": false
          },
          {
            "fieldPath": "trojanBean",
            "columnName": "trojanBean",
            "affinity": "BLOB",
            "notNull": false
          },
          {
            "fieldPath": "trojanGoBean",
            "columnName": "trojanGoBean",
            "affinity": "BLOB",
            "notNull": false
          },
          {
            "fieldPath": "mieruBean",
            "columnName": "mieruBean",
            "affinity": "BLOB",
            "notNull": false
          },
          {
            "fieldPath": "naiveBean",
            "columnName": "naiveBean",
            "affinity": "BLOB",
            "notNull": false
          },
          {
            "fieldPath": "hysteriaBean",
            "columnName": "hysteriaBean",
            "affinity": "BLOB",
            "notNull": false
          },
          {
            "fieldPath": "tuicBean",
            "columnName": "tuicBean",
            "affinity": "BLOB",
            "notNull": false
          },
          {
            "fieldPath": "sshBean",
            "columnName": "sshBean",
            "affinity": "BLOB",
            "notNull": false
          },
          {
            "fieldPath": "wgBean",
            "columnName": "wgBean",
            "affinity": "BLOB",
            "notNull": false
          },
          {
            "fieldPath": "shadowTLSBean",
            "columnName": "shadowTLSBean",
            "affinity": "BLOB",
            "notNull": false
          },
          {
            "fieldPath": "chainBean",
            "columnName": "chainBean",
            "affinity": "BLOB",
            "notNull": false
          },
          {
            "fieldPath": "nekoBean",
            "columnName": "nekoBean",
            "affinity": "BLOB",
            "notNull": false
          },
          {
            "fieldPath": "configBean",
            "columnName": "configBean",
            "affinity": "BLOB",
            "notNull": false
          }
        ],
        "primaryKey": {
          "autoGenerate": true,
          "columnNames": [
            "id"
          ]
        },
        "indices": [
          {
            "name": "groupId",
            "unique": false,
            "columnNames": [
              "groupId"
            ],
            "orders": [],
            "createSql": "CREATE INDEX IF NOT EXISTS `groupId` ON `${TABLE_NAME}` (`groupId`)"
          }
        ],
        "foreignKeys": []
      },
      {
        "tableName": "rules",
        "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `name` TEXT NOT NULL, `userOrder` INTEGER NOT NULL, `enabled` INTEGER NOT NULL, `domains` TEXT NOT NULL, `ip` TEXT NOT NULL, `port` TEXT NOT NULL, `sourcePort` TEXT NOT NULL, `network` TEXT NOT NULL, `source` TEXT NOT NULL, `protocol` TEXT NOT NULL, `outbound` INTEGER NOT NULL, `packages` TEXT NOT NULL)",
        "fields": [
          {
            "fieldPath": "id",
            "columnName": "id",
            "affinity": "INTEGER",
            "notNull": true
          },
          {
            "fieldPath": "name",
            "columnName": "name",
            "affinity": "TEXT",
            "notNull": true
          },
          {
            "fieldPath": "userOrder",
            "columnName": "userOrder",
            "affinity": "INTEGER",
            "notNull": true
          },
          {
            "fieldPath": "enabled",
            "columnName": "enabled",
            "affinity": "INTEGER",
            "notNull": true
          },
          {
            "fieldPath": "domains",
            "columnName": "domains",
            "affinity": "TEXT",
            "notNull": true
          },
          {
            "fieldPath": "ip",
            "columnName": "ip",
            "affinity": "TEXT",
            "notNull": true
          },
          {
            "fieldPath": "port",
            "columnName": "port",
            "affinity": "TEXT",
            "notNull": true
          },
          {
            "fieldPath": "sourcePort",
            "columnName": "sourcePort",
            "affinity": "TEXT",
            "notNull": true
          },
          {
            "fieldPath": "network",
            "columnName": "network",
            "affinity": "TEXT",
            "notNull": true
          },
          {
            "fieldPath": "source",
            "columnName": "source",
            "affinity": "TEXT",
            "notNull": true
          },
          {
            "fieldPath": "protocol",
            "columnName": "protocol",
            "affinity": "TEXT",
            "notNull": true
          },
          {
            "fieldPath": "outbound",
            "columnName": "outbound",
            "affinity": "INTEGER",
            "notNull": true
          },
          {
            "fieldPath": "packages",
            "columnName": "packages",
            "affinity": "TEXT",
            "notNull": true
          }
        ],
        "primaryKey": {
          "autoGenerate": true,
          "columnNames": [
            "id"
          ]
        },
        "indices": [],
        "foreignKeys": []
      }
    ],
    "views": [],
    "setupQueries": [
      "CREATE TABLE IF NOT EXISTS room_master_table (id INTEGER PRIMARY KEY,identity_hash TEXT)",
      "INSERT OR REPLACE INTO room_master_table (id,identity_hash) VALUES(42, 'cff00d0142d9e53d2ca24a6a55cd213c')"
    ]
  }
}

================================================
FILE: app/schemas/io.nekohasekai.sagernet.database.SagerDatabase/5.json
================================================
{
  "formatVersion": 1,
  "database": {
    "version": 5,
    "identityHash": "1dbf667053726c13d139a4d83c41f895",
    "entities": [
      {
        "tableName": "proxy_groups",
        "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `userOrder` INTEGER NOT NULL, `ungrouped` INTEGER NOT NULL, `name` TEXT, `type` INTEGER NOT NULL, `subscription` BLOB, `order` INTEGER NOT NULL, `isSelector` INTEGER NOT NULL, `frontProxy` INTEGER NOT NULL, `landingProxy` INTEGER NOT NULL)",
        "fields": [
          {
            "fieldPath": "id",
            "columnName": "id",
            "affinity": "INTEGER",
            "notNull": true
          },
          {
            "fieldPath": "userOrder",
            "columnName": "userOrder",
            "affinity": "INTEGER",
            "notNull": true
          },
          {
            "fieldPath": "ungrouped",
            "columnName": "ungrouped",
            "affinity": "INTEGER",
            "notNull": true
          },
          {
            "fieldPath": "name",
            "columnName": "name",
            "affinity": "TEXT",
            "notNull": false
          },
          {
            "fieldPath": "type",
            "columnName": "type",
            "affinity": "INTEGER",
            "notNull": true
          },
          {
            "fieldPath": "subscription",
            "columnName": "subscription",
            "affinity": "BLOB",
            "notNull": false
          },
          {
            "fieldPath": "order",
            "columnName": "order",
            "affinity": "INTEGER",
            "notNull": true
          },
          {
            "fieldPath": "isSelector",
            "columnName": "isSelector",
            "affinity": "INTEGER",
            "notNull": true
          },
          {
            "fieldPath": "frontProxy",
            "columnName": "frontProxy",
            "affinity": "INTEGER",
            "notNull": true
          },
          {
            "fieldPath": "landingProxy",
            "columnName": "landingProxy",
            "affinity": "INTEGER",
            "notNull": true
          }
        ],
        "primaryKey": {
          "autoGenerate": true,
          "columnNames": [
            "id"
          ]
        },
        "indices": [],
        "foreignKeys": []
      },
      {
        "tableName": "proxy_entities",
        "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `groupId` INTEGER NOT NULL, `type` INTEGER NOT NULL, `userOrder` INTEGER NOT NULL, `tx` INTEGER NOT NULL, `rx` INTEGER NOT NULL, `status` INTEGER NOT NULL, `ping` INTEGER NOT NULL, `uuid` TEXT NOT NULL, `error` TEXT, `socksBean` BLOB, `httpBean` BLOB, `ssBean` BLOB, `vmessBean` BLOB, `trojanBean` BLOB, `trojanGoBean` BLOB, `mieruBean` BLOB, `naiveBean` BLOB, `hysteriaBean` BLOB, `tuicBean` BLOB, `sshBean` BLOB, `wgBean` BLOB, `shadowTLSBean` BLOB, `anyTLSBean` BLOB, `chainBean` BLOB, `nekoBean` BLOB, `configBean` BLOB)",
        "fields": [
          {
            "fieldPath": "id",
            "columnName": "id",
            "affinity": "INTEGER",
            "notNull": true
          },
          {
            "fieldPath": "groupId",
            "columnName": "groupId",
            "affinity": "INTEGER",
            "notNull": true
          },
          {
            "fieldPath": "type",
            "columnName": "type",
            "affinity": "INTEGER",
            "notNull": true
          },
          {
            "fieldPath": "userOrder",
            "columnName": "userOrder",
            "affinity": "INTEGER",
            "notNull": true
          },
          {
            "fieldPath": "tx",
            "columnName": "tx",
            "affinity": "INTEGER",
            "notNull": true
          },
          {
            "fieldPath": "rx",
            "columnName": "rx",
            "affinity": "INTEGER",
            "notNull": true
          },
          {
            "fieldPath": "status",
            "columnName": "status",
            "affinity": "INTEGER",
            "notNull": true
          },
          {
            "fieldPath": "ping",
            "columnName": "ping",
            "affinity": "INTEGER",
            "notNull": true
          },
          {
            "fieldPath": "uuid",
            "columnName": "uuid",
            "affinity": "TEXT",
            "notNull": true
          },
          {
            "fieldPath": "error",
            "columnName": "error",
            "affinity": "TEXT",
            "notNull": false
          },
          {
            "fieldPath": "socksBean",
            "columnName": "socksBean",
            "affinity": "BLOB",
            "notNull": false
          },
          {
            "fieldPath": "httpBean",
            "columnName": "httpBean",
            "affinity": "BLOB",
            "notNull": false
          },
          {
            "fieldPath": "ssBean",
            "columnName": "ssBean",
            "affinity": "BLOB",
            "notNull": false
          },
          {
            "fieldPath": "vmessBean",
            "columnName": "vmessBean",
            "affinity": "BLOB",
            "notNull": false
          },
          {
            "fieldPath": "trojanBean",
            "columnName": "trojanBean",
            "affinity": "BLOB",
            "notNull": false
          },
          {
            "fieldPath": "trojanGoBean",
            "columnName": "trojanGoBean",
            "affinity": "BLOB",
            "notNull": false
          },
          {
            "fieldPath": "mieruBean",
            "columnName": "mieruBean",
            "affinity": "BLOB",
            "notNull": false
          },
          {
            "fieldPath": "naiveBean",
            "columnName": "naiveBean",
            "affinity": "BLOB",
            "notNull": false
          },
          {
            "fieldPath": "hysteriaBean",
            "columnName": "hysteriaBean",
            "affinity": "BLOB",
            "notNull": false
          },
          {
            "fieldPath": "tuicBean",
            "columnName": "tuicBean",
            "affinity": "BLOB",
            "notNull": false
          },
          {
            "fieldPath": "sshBean",
            "columnName": "sshBean",
            "affinity": "BLOB",
            "notNull": false
          },
          {
            "fieldPath": "wgBean",
            "columnName": "wgBean",
            "affinity": "BLOB",
            "notNull": false
          },
          {
            "fieldPath": "shadowTLSBean",
            "columnName": "shadowTLSBean",
            "affinity": "BLOB",
            "notNull": false
          },
          {
            "fieldPath": "anyTLSBean",
            "columnName": "anyTLSBean",
            "affinity": "BLOB",
            "notNull": false
          },
          {
            "fieldPath": "chainBean",
            "columnName": "chainBean",
            "affinity": "BLOB",
            "notNull": false
          },
          {
            "fieldPath": "nekoBean",
            "columnName": "nekoBean",
            "affinity": "BLOB",
            "notNull": false
          },
          {
            "fieldPath": "configBean",
            "columnName": "configBean",
            "affinity": "BLOB",
            "notNull": false
          }
        ],
        "primaryKey": {
          "autoGenerate": true,
          "columnNames": [
            "id"
          ]
        },
        "indices": [
          {
            "name": "groupId",
            "unique": false,
            "columnNames": [
              "groupId"
            ],
            "orders": [],
            "createSql": "CREATE INDEX IF NOT EXISTS `groupId` ON `${TABLE_NAME}` (`groupId`)"
          }
        ],
        "foreignKeys": []
      },
      {
        "tableName": "rules",
        "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `name` TEXT NOT NULL, `userOrder` INTEGER NOT NULL, `enabled` INTEGER NOT NULL, `domains` TEXT NOT NULL, `ip` TEXT NOT NULL, `port` TEXT NOT NULL, `sourcePort` TEXT NOT NULL, `network` TEXT NOT NULL, `source` TEXT NOT NULL, `protocol` TEXT NOT NULL, `outbound` INTEGER NOT NULL, `packages` TEXT NOT NULL)",
        "fields": [
          {
            "fieldPath": "id",
            "columnName": "id",
            "affinity": "INTEGER",
            "notNull": true
          },
          {
            "fieldPath": "name",
            "columnName": "name",
            "affinity": "TEXT",
            "notNull": true
          },
          {
            "fieldPath": "userOrder",
            "columnName": "userOrder",
            "affinity": "INTEGER",
            "notNull": true
          },
          {
            "fieldPath": "enabled",
            "columnName": "enabled",
            "affinity": "INTEGER",
            "notNull": true
          },
          {
            "fieldPath": "domains",
            "columnName": "domains",
            "affinity": "TEXT",
            "notNull": true
          },
          {
            "fieldPath": "ip",
            "columnName": "ip",
            "affinity": "TEXT",
            "notNull": true
          },
          {
            "fieldPath": "port",
            "columnName": "port",
            "affinity": "TEXT",
            "notNull": true
          },
          {
            "fieldPath": "sourcePort",
            "columnName": "sourcePort",
            "affinity": "TEXT",
            "notNull": true
          },
          {
            "fieldPath": "network",
            "columnName": "network",
            "affinity": "TEXT",
            "notNull": true
          },
          {
            "fieldPath": "source",
            "columnName": "source",
            "affinity": "TEXT",
            "notNull": true
          },
          {
            "fieldPath": "protocol",
            "columnName": "protocol",
            "affinity": "TEXT",
            "notNull": true
          },
          {
            "fieldPath": "outbound",
            "columnName": "outbound",
            "affinity": "INTEGER",
            "notNull": true
          },
          {
            "fieldPath": "packages",
            "columnName": "packages",
            "affinity": "TEXT",
            "notNull": true
          }
        ],
        "primaryKey": {
          "autoGenerate": true,
          "columnNames": [
            "id"
          ]
        },
        "indices": [],
        "foreignKeys": []
      }
    ],
    "views": [],
    "setupQueries": [
      "CREATE TABLE IF NOT EXISTS room_master_table (id INTEGER PRIMARY KEY,identity_hash TEXT)",
      "INSERT OR REPLACE INTO room_master_table (id,identity_hash) VALUES(42, '1dbf667053726c13d139a4d83c41f895')"
    ]
  }
}

================================================
FILE: app/schemas/io.nekohasekai.sagernet.database.SagerDatabase/6.json
================================================
{
  "formatVersion": 1,
  "database": {
    "version": 6,
    "identityHash": "3d3db9106a89d6f20ef3fde6e81dbaa9",
    "entities": [
      {
        "tableName": "proxy_groups",
        "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `userOrder` INTEGER NOT NULL, `ungrouped` INTEGER NOT NULL, `name` TEXT, `type` INTEGER NOT NULL, `subscription` BLOB, `order` INTEGER NOT NULL, `isSelector` INTEGER NOT NULL, `frontProxy` INTEGER NOT NULL, `landingProxy` INTEGER NOT NULL)",
        "fields": [
          {
            "fieldPath": "id",
            "columnName": "id",
            "affinity": "INTEGER",
            "notNull": true
          },
          {
            "fieldPath": "userOrder",
            "columnName": "userOrder",
            "affinity": "INTEGER",
            "notNull": true
          },
          {
            "fieldPath": "ungrouped",
            "columnName": "ungrouped",
            "affinity": "INTEGER",
            "notNull": true
          },
          {
            "fieldPath": "name",
            "columnName": "name",
            "affinity": "TEXT",
            "notNull": false
          },
          {
            "fieldPath": "type",
            "columnName": "type",
            "affinity": "INTEGER",
            "notNull": true
          },
          {
            "fieldPath": "subscription",
            "columnName": "subscription",
            "affinity": "BLOB",
            "notNull": false
          },
          {
            "fieldPath": "order",
            "columnName": "order",
            "affinity": "INTEGER",
            "notNull": true
          },
          {
            "fieldPath": "isSelector",
            "columnName": "isSelector",
            "affinity": "INTEGER",
            "notNull": true
          },
          {
            "fieldPath": "frontProxy",
            "columnName": "frontProxy",
            "affinity": "INTEGER",
            "notNull": true
          },
          {
            "fieldPath": "landingProxy",
            "columnName": "landingProxy",
            "affinity": "INTEGER",
            "notNull": true
          }
        ],
        "primaryKey": {
          "autoGenerate": true,
          "columnNames": [
            "id"
          ]
        },
        "indices": [],
        "foreignKeys": []
      },
      {
        "tableName": "proxy_entities",
        "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `groupId` INTEGER NOT NULL, `type` INTEGER NOT NULL, `userOrder` INTEGER NOT NULL, `tx` INTEGER NOT NULL, `rx` INTEGER NOT NULL, `status` INTEGER NOT NULL, `ping` INTEGER NOT NULL, `uuid` TEXT NOT NULL, `error` TEXT, `socksBean` BLOB, `httpBean` BLOB, `ssBean` BLOB, `vmessBean` BLOB, `trojanBean` BLOB, `trojanGoBean` BLOB, `mieruBean` BLOB, `naiveBean` BLOB, `hysteriaBean` BLOB, `tuicBean` BLOB, `sshBean` BLOB, `wgBean` BLOB, `shadowTLSBean` BLOB, `anyTLSBean` BLOB, `chainBean` BLOB, `nekoBean` BLOB, `configBean` BLOB)",
        "fields": [
          {
            "fieldPath": "id",
            "columnName": "id",
            "affinity": "INTEGER",
            "notNull": true
          },
          {
            "fieldPath": "groupId",
            "columnName": "groupId",
            "affinity": "INTEGER",
            "notNull": true
          },
          {
            "fieldPath": "type",
            "columnName": "type",
            "affinity": "INTEGER",
            "notNull": true
          },
          {
            "fieldPath": "userOrder",
            "columnName": "userOrder",
            "affinity": "INTEGER",
            "notNull": true
          },
          {
            "fieldPath": "tx",
            "columnName": "tx",
            "affinity": "INTEGER",
            "notNull": true
          },
          {
            "fieldPath": "rx",
            "columnName": "rx",
            "affinity": "INTEGER",
            "notNull": true
          },
          {
            "fieldPath": "status",
            "columnName": "status",
            "affinity": "INTEGER",
            "notNull": true
          },
          {
            "fieldPath": "ping",
            "columnName": "ping",
            "affinity": "INTEGER",
            "notNull": true
          },
          {
            "fieldPath": "uuid",
            "columnName": "uuid",
            "affinity": "TEXT",
            "notNull": true
          },
          {
            "fieldPath": "error",
            "columnName": "error",
            "affinity": "TEXT",
            "notNull": false
          },
          {
            "fieldPath": "socksBean",
            "columnName": "socksBean",
            "affinity": "BLOB",
            "notNull": false
          },
          {
            "fieldPath": "httpBean",
            "columnName": "httpBean",
            "affinity": "BLOB",
            "notNull": false
          },
          {
            "fieldPath": "ssBean",
            "columnName": "ssBean",
            "affinity": "BLOB",
            "notNull": false
          },
          {
            "fieldPath": "vmessBean",
            "columnName": "vmessBean",
            "affinity": "BLOB",
            "notNull": false
          },
          {
            "fieldPath": "trojanBean",
            "columnName": "trojanBean",
            "affinity": "BLOB",
            "notNull": false
          },
          {
            "fieldPath": "trojanGoBean",
            "columnName": "trojanGoBean",
            "affinity": "BLOB",
            "notNull": false
          },
          {
            "fieldPath": "mieruBean",
            "columnName": "mieruBean",
            "affinity": "BLOB",
            "notNull": false
          },
          {
            "fieldPath": "naiveBean",
            "columnName": "naiveBean",
            "affinity": "BLOB",
            "notNull": false
          },
          {
            "fieldPath": "hysteriaBean",
            "columnName": "hysteriaBean",
            "affinity": "BLOB",
            "notNull": false
          },
          {
            "fieldPath": "tuicBean",
            "columnName": "tuicBean",
            "affinity": "BLOB",
            "notNull": false
          },
          {
            "fieldPath": "sshBean",
            "columnName": "sshBean",
            "affinity": "BLOB",
            "notNull": false
          },
          {
            "fieldPath": "wgBean",
            "columnName": "wgBean",
            "affinity": "BLOB",
            "notNull": false
          },
          {
            "fieldPath": "shadowTLSBean",
            "columnName": "shadowTLSBean",
            "affinity": "BLOB",
            "notNull": false
          },
          {
            "fieldPath": "anyTLSBean",
            "columnName": "anyTLSBean",
            "affinity": "BLOB",
            "notNull": false
          },
          {
            "fieldPath": "chainBean",
            "columnName": "chainBean",
            "affinity": "BLOB",
            "notNull": false
          },
          {
            "fieldPath": "nekoBean",
            "columnName": "nekoBean",
            "affinity": "BLOB",
            "notNull": false
          },
          {
            "fieldPath": "configBean",
            "columnName": "configBean",
            "affinity": "BLOB",
            "notNull": false
          }
        ],
        "primaryKey": {
          "autoGenerate": true,
          "columnNames": [
            "id"
          ]
        },
        "indices": [
          {
            "name": "groupId",
            "unique": false,
            "columnNames": [
              "groupId"
            ],
            "orders": [],
            "createSql": "CREATE INDEX IF NOT EXISTS `groupId` ON `${TABLE_NAME}` (`groupId`)"
          }
        ],
        "foreignKeys": []
      },
      {
        "tableName": "rules",
        "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `name` TEXT NOT NULL, `config` TEXT NOT NULL DEFAULT '', `userOrder` INTEGER NOT NULL, `enabled` INTEGER NOT NULL, `domains` TEXT NOT NULL, `ip` TEXT NOT NULL, `port` TEXT NOT NULL, `sourcePort` TEXT NOT NULL, `network` TEXT NOT NULL, `source` TEXT NOT NULL, `protocol` TEXT NOT NULL, `outbound` INTEGER NOT NULL, `packages` TEXT NOT NULL)",
        "fields": [
          {
            "fieldPath": "id",
            "columnName": "id",
            "affinity": "INTEGER",
            "notNull": true
          },
          {
            "fieldPath": "name",
            "columnName": "name",
            "affinity": "TEXT",
            "notNull": true
          },
          {
            "fieldPath": "config",
            "columnName": "config",
            "affinity": "TEXT",
            "notNull": true,
            "defaultValue": "''"
          },
          {
            "fieldPath": "userOrder",
            "columnName": "userOrder",
            "affinity": "INTEGER",
            "notNull": true
          },
          {
            "fieldPath": "enabled",
            "columnName": "enabled",
            "affinity": "INTEGER",
            "notNull": true
          },
          {
            "fieldPath": "domains",
            "columnName": "domains",
            "affinity": "TEXT",
            "notNull": true
          },
          {
            "fieldPath": "ip",
            "columnName": "ip",
            "affinity": "TEXT",
            "notNull": true
          },
          {
            "fieldPath": "port",
            "columnName": "port",
            "affinity": "TEXT",
            "notNull": true
          },
          {
            "fieldPath": "sourcePort",
            "columnName": "sourcePort",
            "affinity": "TEXT",
            "notNull": true
          },
          {
            "fieldPath": "network",
            "columnName": "network",
            "affinity": "TEXT",
            "notNull": true
          },
          {
            "fieldPath": "source",
            "columnName": "source",
            "affinity": "TEXT",
            "notNull": true
          },
          {
            "fieldPath": "protocol",
            "columnName": "protocol",
            "affinity": "TEXT",
            "notNull": true
          },
          {
            "fieldPath": "outbound",
            "columnName": "outbound",
            "affinity": "INTEGER",
            "notNull": true
          },
          {
            "fieldPath": "packages",
            "columnName": "packages",
            "affinity": "TEXT",
            "notNull": true
          }
        ],
        "primaryKey": {
          "autoGenerate": true,
          "columnNames": [
            "id"
          ]
        },
        "indices": [],
        "foreignKeys": []
      }
    ],
    "views": [],
    "setupQueries": [
      "CREATE TABLE IF NOT EXISTS room_master_table (id INTEGER PRIMARY KEY,identity_hash TEXT)",
      "INSERT OR REPLACE INTO room_master_table (id,identity_hash) VALUES(42, '3d3db9106a89d6f20ef3fde6e81dbaa9')"
    ]
  }
}

================================================
FILE: app/schemas/io.nekohasekai.sagernet.database.preference.PublicDatabase/1.json
================================================
{
  "formatVersion": 1,
  "database": {
    "version": 1,
    "identityHash": "f1aab1fb633378621635c344dbc8ac7b",
    "entities": [
      {
        "tableName": "KeyValuePair",
        "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`key` TEXT NOT NULL, `valueType` INTEGER NOT NULL, `value` BLOB NOT NULL, PRIMARY KEY(`key`))",
        "fields": [
          {
            "fieldPath": "key",
            "columnName": "key",
            "affinity": "TEXT",
            "notNull": true
          },
          {
            "fieldPath": "valueType",
            "columnName": "valueType",
            "affinity": "INTEGER",
            "notNull": true
          },
          {
            "fieldPath": "value",
            "columnName": "value",
            "affinity": "BLOB",
            "notNull": true
          }
        ],
        "primaryKey": {
          "columnNames": [
            "key"
          ],
          "autoGenerate": false
        },
        "indices": [],
        "foreignKeys": []
      }
    ],
    "views": [],
    "setupQueries": [
      "CREATE TABLE IF NOT EXISTS room_master_table (id INTEGER PRIMARY KEY,identity_hash TEXT)",
      "INSERT OR REPLACE INTO room_master_table (id,identity_hash) VALUES(42, 'f1aab1fb633378621635c344dbc8ac7b')"
    ]
  }
}

================================================
FILE: app/schemas/moe.matsuri.nb4a.TempDatabase/1.json
================================================
{
  "formatVersion": 1,
  "database": {
    "version": 1,
    "identityHash": "f1aab1fb633378621635c344dbc8ac7b",
    "entities": [
      {
        "tableName": "KeyValuePair",
        "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`key` TEXT NOT NULL, `valueType` INTEGER NOT NULL, `value` BLOB NOT NULL, PRIMARY KEY(`key`))",
        "fields": [
          {
            "fieldPath": "key",
            "columnName": "key",
            "affinity": "TEXT",
            "notNull": true
          },
          {
            "fieldPath": "valueType",
            "columnName": "valueType",
            "affinity": "INTEGER",
            "notNull": true
          },
          {
            "fieldPath": "value",
            "columnName": "value",
            "affinity": "BLOB",
            "notNull": true
          }
        ],
        "primaryKey": {
          "columnNames": [
            "key"
          ],
          "autoGenerate": false
        },
        "indices": [],
        "foreignKeys": []
      }
    ],
    "views": [],
    "setupQueries": [
      "CREATE TABLE IF NOT EXISTS room_master_table (id INTEGER PRIMARY KEY,identity_hash TEXT)",
      "INSERT OR REPLACE INTO room_master_table (id,identity_hash) VALUES(42, 'f1aab1fb633378621635c344dbc8ac7b')"
    ]
  }
}

================================================
FILE: app/src/main/AndroidManifest.xml
================================================
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:installLocation="internalOnly">

    <uses-sdk tools:overrideLibrary="com.google.zxing.client.android, com.blacksquircle.ui.editorkit" />

    <permission
        android:name="${applicationId}.SERVICE"
        android:protectionLevel="signature" />

    <uses-permission android:name="${applicationId}.SERVICE" />
    <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
    <uses-permission android:name="android.permission.CHANGE_NETWORK_STATE" />
    <uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
    <uses-permission android:name="android.permission.FOREGROUND_SERVICE_SYSTEM_EXEMPTED" />
    <uses-permission android:name="android.permission.INTERNET" />
    <uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
    <uses-permission android:name="android.permission.WAKE_LOCK" />
    <uses-permission android:name="android.permission.POST_NOTIFICATIONS" />
    <uses-permission android:name="android.permission.EXPAND_STATUS_BAR" />

    <uses-permission
        android:name="android.permission.QUERY_ALL_PACKAGES"
        tools:ignore="PackageVisibilityPolicy" />
    <uses-permission android:name="com.android.permission.GET_INSTALLED_APPS" />

    <uses-permission android:name="android.permission.CAMERA" />
    <uses-permission android:name="android.permission.REQUEST_IGNORE_BATTERY_OPTIMIZATIONS" />

    <uses-feature
        android:name="android.software.leanback"
        android:required="false" />
    <uses-feature
        android:name="android.hardware.touchscreen"
        android:required="false" />
    <uses-feature
        android:name="android.hardware.camera"
        android:required="false" />
    <uses-feature
        android:name="android.hardware.camera.autofocus"
        android:required="false" />

    <queries>
        <intent>
            <action android:name="io.nekohasekai.sagernet.plugin.ACTION_NATIVE_PLUGIN" />
        </intent>
    </queries>

    <application
        android:name="io.nekohasekai.sagernet.SagerNet"
        android:allowBackup="true"
        android:autoRevokePermissions="allowed"
        android:banner="@mipmap/ic_launcher"
        android:dataExtractionRules="@xml/backup_rules"
        android:fullBackupContent="@xml/backup_descriptor"
        android:fullBackupOnly="true"
        android:hardwareAccelerated="true"
        android:hasFragileUserData="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:largeHeap="true"
        android:networkSecurityConfig="@xml/network_security_config"
        android:roundIcon="@mipmap/ic_launcher"
        android:supportsRtl="true"
        android:theme="@style/Theme.Start">
        <meta-data
            android:name="android.app.shortcuts"
            android:resource="@xml/shortcuts" />

        <activity
            android:name="io.nekohasekai.sagernet.ui.BlankActivity"
            android:configChanges="uiMode" />

        <activity
            android:name="io.nekohasekai.sagernet.ui.MainActivity"
            android:configChanges="uiMode"
            android:exported="true"
            android:launchMode="singleTask">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>

            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LEANBACK_LAUNCHER" />
            </intent-filter>
            <intent-filter>
                <action android:name="android.service.quicksettings.action.QS_TILE_PREFERENCES" />
            </intent-filter>

            <intent-filter android:label="@string/subscription_import">
                <action android:name="android.intent.action.VIEW" />

                <category android:name="android.intent.category.DEFAULT" />
                <category android:name="android.intent.category.BROWSABLE" />

                <data
                    android:host="subscription"
                    android:scheme="sn" />

            </intent-filter>

            <intent-filter android:label="@string/subscription_import">
                <action android:name="android.intent.action.VIEW" />

                <category android:name="android.intent.category.DEFAULT" />
                <category android:name="android.intent.category.BROWSABLE" />

                <data
                    android:host="install-config"
                    android:scheme="clash" />
            </intent-filter>

            <intent-filter android:label="@string/profile_import">
                <action android:name="android.intent.action.VIEW" />

                <category android:name="android.intent.category.DEFAULT" />
                <category android:name="android.intent.category.BROWSABLE" />

                <data android:scheme="sn" />
                <data android:scheme="ss" />
                <data android:scheme="ssr" />
                <data android:scheme="socks" />
                <data android:scheme="socks4" />
                <data android:scheme="socksa" />
                <data android:scheme="sock5" />
                <data android:scheme="vmess" />
                <data android:scheme="trojan" />
                <data android:scheme="trojan-go" />
                <data android:scheme="naive+https" />
                <data android:scheme="naive+quic" />
                <data android:scheme="hysteria" />

            </intent-filter>

            <meta-data
                android:name="android.app.shortcuts"
                android:resource="@xml/shortcuts" />
        </activity>
        <activity
            android:name="io.nekohasekai.sagernet.ui.VpnRequestActivity"
            android:excludeFromRecents="true"
            android:taskAffinity="" />
        <activity
            android:name="io.nekohasekai.sagernet.ui.profile.ConfigEditActivity"
            android:configChanges="uiMode" />
        <activity
            android:name="io.nekohasekai.sagernet.ui.profile.SocksSettingsActivity"
            android:configChanges="uiMode" />
        <activity
            android:name="io.nekohasekai.sagernet.ui.profile.HttpSettingsActivity"
            android:configChanges="uiMode" />
        <activity
            android:name="io.nekohasekai.sagernet.ui.profile.ShadowsocksSettingsActivity"
            android:configChanges="uiMode" />
        <activity
            android:name="io.nekohasekai.sagernet.ui.profile.VMessSettingsActivity"
            android:configChanges="uiMode" />
        <activity
            android:name="io.nekohasekai.sagernet.ui.profile.TrojanSettingsActivity"
            android:configChanges="uiMode" />
        <activity
            android:name="io.nekohasekai.sagernet.ui.profile.TrojanGoSettingsActivity"
            android:configChanges="uiMode" />
        <activity
            android:name="io.nekohasekai.sagernet.ui.profile.MieruSettingsActivity"
            android:configChanges="uiMode" />
        <activity
            android:name="io.nekohasekai.sagernet.ui.profile.NaiveSettingsActivity"
            android:configChanges="uiMode" />
        <activity
            android:name="io.nekohasekai.sagernet.ui.profile.HysteriaSettingsActivity"
            android:configChanges="uiMode" />
        <activity
            android:name="io.nekohasekai.sagernet.ui.profile.SSHSettingsActivity"
            android:configChanges="uiMode" />
        <activity
            android:name="io.nekohasekai.sagernet.ui.profile.WireGuardSettingsActivity"
            android:configChanges="uiMode" />
        <activity
            android:name="io.nekohasekai.sagernet.ui.profile.TuicSettingsActivity"
            android:configChanges="uiMode" />
        <activity
            android:name="io.nekohasekai.sagernet.ui.profile.ChainSettingsActivity"
            android:configChanges="uiMode" />
        <activity
            android:name="moe.matsuri.nb4a.proxy.shadowtls.ShadowTLSSettingsActivity"
            android:configChanges="uiMode" />
        <activity
            android:name="moe.matsuri.nb4a.proxy.anytls.AnyTLSSettingsActivity"
            android:configChanges="uiMode" />
        <activity
            android:name="moe.matsuri.nb4a.proxy.config.ConfigSettingActivity"
            android:configChanges="uiMode" />
        <activity
            android:name="io.nekohasekai.sagernet.ui.GroupSettingsActivity"
            android:configChanges="uiMode" />
        <activity
            android:name="io.nekohasekai.sagernet.ui.RouteSettingsActivity"
            android:configChanges="uiMode" />
        <activity
            android:name="io.nekohasekai.sagernet.ui.AssetsActivity"
            android:configChanges="uiMode" />
        <activity
            android:name="io.nekohasekai.sagernet.ui.AppListActivity"
            android:configChanges="uiMode" />
        <activity
            android:name=".QuickToggleShortcut"
            android:excludeFromRecents="true"
            android:exported="true"
            android:label="@string/quick_toggle"
            android:launchMode="singleTask"
            android:process=":bg"
            android:taskAffinity=""
            android:theme="@android:style/Theme.Translucent.NoTitleBar">
            <intent-filter>
                <action android:name="android.intent.action.CREATE_SHORTCUT" />
            </intent-filter>
        </activity>
        <activity
            android:name="io.nekohasekai.sagernet.ui.QuickEnableShortcut"
            android:excludeFromRecents="true"
            android:exported="true"
            android:label="@string/quick_enable"
            android:launchMode="singleTask"
            android:process=":bg"
            android:taskAffinity=""
            android:theme="@android:style/Theme.Translucent.NoTitleBar" />
        <activity
            android:name="io.nekohasekai.sagernet.ui.QuickDisableShortcut"
            android:excludeFromRecents="true"
            android:exported="true"
            android:label="@string/quick_disable"
            android:launchMode="singleTask"
            android:process=":bg"
            android:taskAffinity=""
            android:theme="@android:style/Theme.Translucent.NoTitleBar" />
        <activity
            android:name="io.nekohasekai.sagernet.ui.AppManagerActivity"
            android:configChanges="uiMode"
            android:excludeFromRecents="true"
            android:label="@string/proxied_apps"
            android:launchMode="singleTask"
            android:parentActivityName=".ui.MainActivity" />
        <activity
            android:name="io.nekohasekai.sagernet.ui.ScannerActivity"
            android:configChanges="uiMode"
            android:excludeFromRecents="true"
            android:label="@string/add_profile_methods_scan_qr_code"
            android:launchMode="singleTask"
            android:parentActivityName="io.nekohasekai.sagernet.ui.MainActivity" />
        <activity
            android:name="io.nekohasekai.sagernet.ui.ProfileSelectActivity"
            android:configChanges="uiMode"
            android:label="@string/select_profile"
            android:launchMode="singleTask"
            android:parentActivityName="io.nekohasekai.sagernet.ui.MainActivity" />
        <activity
            android:name="io.nekohasekai.sagernet.ui.StunActivity"
            android:configChanges="uiMode"
            android:launchMode="singleTask"
            android:parentActivityName="io.nekohasekai.sagernet.ui.MainActivity" />

        <activity
            android:name="io.nekohasekai.sagernet.ui.SwitchActivity"
            android:configChanges="uiMode"
            android:excludeFromRecents="true"
            android:launchMode="singleInstance"
            android:theme="@style/Theme.SagerNet.Dialog" />

        <service
            android:name="io.nekohasekai.sagernet.bg.ProxyService"
            android:exported="false"
            android:foregroundServiceType="systemExempted"
            android:process=":bg"
            tools:ignore="ForegroundServicePermission" />

        <service
            android:name="io.nekohasekai.sagernet.bg.VpnService"
            android:exported="false"
            android:foregroundServiceType="systemExempted"
            android:label="@string/app_name"
            android:permission="android.permission.BIND_VPN_SERVICE"
            android:process=":bg"
            tools:ignore="ForegroundServicePermission">

            <intent-filter>
                <action android:name="android.net.VpnService" />
            </intent-filter>
        </service>

        <service
            android:name="io.nekohasekai.sagernet.bg.TileService"
            android:exported="true"
            android:foregroundServiceType="systemExempted"
            android:icon="@drawable/ic_service_active"
            android:label="@string/tile_title"
            android:permission="android.permission.BIND_QUICK_SETTINGS_TILE"
            android:process=":bg"
            tools:ignore="ForegroundServicePermission"
            tools:targetApi="n">
            <intent-filter>
                <action android:name="android.service.quicksettings.action.QS_TILE" />
            </intent-filter>
            <meta-data
                android:name="android.service.quicksettings.TOGGLEABLE_TILE"
                android:value="true" />
        </service>

        <provider
            android:name="androidx.core.content.FileProvider"
            android:authorities="${applicationId}.cache"
            android:exported="false"
            android:grantUriPermissions="true">
            <meta-data
                android:name="android.support.FILE_PROVIDER_PATHS"
                android:resource="@xml/cache_paths" />
        </provider>

        <provider
            android:name="androidx.startup.InitializationProvider"
            android:authorities="${applicationId}.androidx-startup"
            tools:node="remove" />

        <receiver
            android:name="io.nekohasekai.sagernet.BootReceiver"
            android:enabled="false"
            android:exported="true"
            android:process=":bg">
            <intent-filter>
                <action android:name="android.intent.action.BOOT_COMPLETED" />
                <action android:name="android.intent.action.LOCKED_BOOT_COMPLETED" />
                <action android:name="android.intent.action.MY_PACKAGE_REPLACED" />
            </intent-filter>
        </receiver>

        <service
            android:name="androidx.room.MultiInstanceInvalidationService"
            android:process=":bg" />

    </application>

</manifest>

================================================
FILE: app/src/main/aidl/io/nekohasekai/sagernet/aidl/ISagerNetService.aidl
================================================
package io.nekohasekai.sagernet.aidl;

import io.nekohasekai.sagernet.aidl.ISagerNetServiceCallback;

interface ISagerNetService {
  int getState();
  String getProfileName();

  void registerCallback(in ISagerNetServiceCallback cb, int id);
  oneway void unregisterCallback(in ISagerNetServiceCallback cb);

  int urlTest();
}


================================================
FILE: app/src/main/aidl/io/nekohasekai/sagernet/aidl/ISagerNetServiceCallback.aidl
================================================
package io.nekohasekai.sagernet.aidl;

import io.nekohasekai.sagernet.aidl.SpeedDisplayData;
import io.nekohasekai.sagernet.aidl.TrafficData;

oneway interface ISagerNetServiceCallback {
  void stateChanged(int state, String profileName, String msg);
  void missingPlugin(String profileName, String pluginName);
  void cbSpeedUpdate(in SpeedDisplayData stats);
  void cbTrafficUpdate(in TrafficData stats);
  void cbSelectorUpdate(long id);
}


================================================
FILE: app/src/main/aidl/io/nekohasekai/sagernet/aidl/SpeedDisplayData.aidl
================================================
package io.nekohasekai.sagernet.aidl;

parcelable SpeedDisplayData;


================================================
FILE: app/src/main/aidl/io/nekohasekai/sagernet/aidl/TrafficData.aidl
================================================
package io.nekohasekai.sagernet.aidl;

parcelable TrafficData;


================================================
FILE: app/src/main/assets/LICENSE
================================================
Copyright (C) 2021 by nekohasekai
<contact-sagernet@sekai.icu>

This program is free software: you can
redistribute it and/or modify it under
the terms of the GNU General Public License
as published by the Free Software Foundation,
either version 3 of the License,
or (at your option) any later version.

This program is distributed in the hope
that it will be useful, but WITHOUT ANY WARRANTY;
without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
See the GNU General Public License for more details.

You should have received a copy of the
GNU General Public License along with this program.
If not, see <http://www.gnu.org/licenses/>.

================================================
FILE: app/src/main/assets/proxy_packagename.txt
================================================
amanita_design.samorost3.gp
android
au.com.shiftyjelly.pocketcasts
bbc.mobile.news.ww
be.mygod.vpnhotspot
ch.protonmail.android
cm.aptoide.pt
co.wanqu.android
com.alphainventor.filemanager
com.amazon.kindle
com.amazon.mshop.android.shopping
com.android.chrome
com.android.providers.downloads
com.android.providers.downloads.ui
com.android.providers.telephony
com.android.settings
com.android.vending
com.android6park.m6park
com.apkpure.aegon
com.apkupdater
com.app.pornhub
com.arthurivanets.owly
com.asahi.tida.tablet
com.authy.authy
com.avmovie
com.ballistiq.artstation
com.binance.dev
com.bitly.app
com.brave.browser
com.brave.browser_beta
com.breel.wallpapers18
com.bvanced.android.youtube
com.chrome.beta
com.chrome.canary
com.chrome.dev
com.cl.newt66y
com.cradle.iitc_mobile
org.exarhteam.iitc_mobile
com.cygames.shadowverse
com.dcard.freedom
com.devhd.feedly
com.devolver.reigns2
com.discord
com.downloader.video.tumblr
com.driverbrowser
com.dropbox.android
com.duolingo
com.duckduckgo.mobile.android
com.dv.adm
com.estrongs.android.pop
com.estrongs.android.pop.pro
com.evernote
com.facebook.katana
com.facebook.lite
com.facebook.mlite
com.facebook.orca
com.facebook.services
com.facebook.system
com.fastaccess.github
com.felixfilip.scpae
com.fireproofstudios.theroom4
com.firstrowria.pushnotificationtester
com.flyersoft.moonreaderp
com.fooview.android.fooview
com.fvd.eversync
com.gameloft.android.anmp.glofta8hm
com.gameloft.android.anmp.glofta9hm
com.gianlu.aria2app
com.github.yeriomin.yalpstore
com.google.android.apps.adm
com.google.android.apps.books
com.google.android.apps.docs
com.google.android.apps.docs.editors.sheets
com.google.android.apps.docs.editors.docs
com.google.android.apps.docs.editors.slides
com.google.android.apps.fitness
com.google.android.apps.googleassistant
com.google.android.apps.googlevoice
com.google.android.apps.hangoutsdialer
com.google.android.apps.inbox
com.google.android.apps.magazines
com.google.android.apps.maps
com.google.android.apps.nbu.files
com.google.android.apps.paidtasks
com.google.android.apps.pdfviewer
com.google.android.apps.photos
com.google.android.apps.plus
com.google.android.apps.translate
com.google.android.gm
com.google.android.gms
com.google.android.gms.setup
com.google.android.googlequicksearchbox
com.google.android.gsf
com.google.android.gsf.login
com.google.android.ims
com.google.android.inputmethod.latin
com.google.android.instantapps.supervisor
com.google.android.keep
com.google.android.music
com.google.android.ogyoutube
com.google.android.partnersetup
com.google.android.play.games
com.google.android.street
com.google.android.syncadapters.calendar
com.google.android.syncadapters.contacts
com.google.android.talk
com.google.android.tts
com.google.android.videos
com.google.android.youtube
com.google.ar.lens
com.google.android.apps.authenticator2
com.hochan.coldsoup
com.ifttt.ifttt
com.imgur.mobile
com.innologica.inoreader
com.instagram.android
com.instagram.lite
com.instapaper.android
com.jarvanh.vpntether
com.kapp.youtube.final
com.klinker.android.twitter_l
com.lastpass.lpandroid
com.linecorp.linelite
com.lingodeer
com.ltnnews.news
com.mediapods.tumbpods
com.mgoogle.android.gms
com.microsoft.emmx
com.microsoft.office.powerpoint
com.microsoft.skydrive
com.mixplorer
com.msd.consumerchinese
com.msd.professionalchinese
com.mss2011c.sharehelper
com.netflix.mediaclient
com.newin.nplayer.pro
com.nianticlabs.ingress.prime.qa
com.nianticproject.ingress
com.ninefolders.hd3
com.ninegag.android.app
com.nintendo.zara
com.nytimes.cn
com.oasisfeng.island
com.ocnt.liveapp.hw
com.orekie.search
com.patreon.android
com.paypal.android.p2pmobile
com.perol.asdpl.pixivez
com.pinterest
com.popularapp.periodcalendar
com.popularapp.videodownloaderforinstagram
com.pushbullet.android
com.quoord.tapatalkpro.activity
com.quora.android
com.rayark.cytus2
com.rayark.implosion
com.rayark.pluto
com.reddit.frontpage
com.resilio.sync
com.rhmsoft.edit
com.rubenmayayo.reddit
com.sec.android.app.sbrowser
com.sec.android.app.sbrowser.beta
com.shanga.walli
com.simplehabit.simplehabitapp
com.slack
com.snaptube.premium
com.sololearn
com.sonelli.juicessh
com.sparkslab.dcardreader
com.spotify.music
com.spotify.lite
com.tencent.huatuo
com.termux
com.teslacoilsw.launcher
com.theinitium.news
com.thomsonreuters.reuters
com.thunkable.android.hritvik00.freenom
com.topjohnwu.magisk
com.tripadvisor.tripadvisor
com.tumblr
com.twitter.android
com.u91porn
com.u9porn
com.ubisoft.dance.justdance2015companion
com.udn.news
com.utopia.pxview
com.valvesoftware.android.steam.community
com.vanced.manager
com.vanced.android.youtube
com.vanced.android.apps.youtube.music
com.mgoogle.android.gms
com.vimeo.android.videoapp
com.vivaldi.browser
com.vivaldi.browser.snapshot
com.vkontakte.android
com.whatsapp
com.wire
com.wuxiangai.refactor
com.xda.labs
com.xvideos.app
com.yahoo.mobile.client.android.superapp
com.yandex.browser
com.yandex.browser.beta
com.yandex.browser.alpha
com.z28j.feel
com.zhiliaoapp.musically
con.medium.reader
de.apkgrabber
de.robv.android.xposed.installer
dk.tacit.android.foldersync.full
es.rafalense.telegram.themes
es.rafalense.themes
flipboard.app
fm.moon.app
fr.gouv.etalab.mastodon
github.tornaco.xposedmoduletest
idm.internet.download.manager
idm.internet.download.manager.plus
io.github.javiewer
io.github.skyhacker2.magnetsearch
io.va.exposed
it.mvilla.android.fenix2
jp.bokete.app.android
jp.naver.line.android
jp.pxv.android
luo.speedometergpspro
m.cna.com.tw.App
mark.via.gp
me.tshine.easymark
net.teeha.android.url_shortener
net.tsapps.appsales
onion.fire
org.fdroid.fdroid
org.freedownloadmanager.fdm
org.kustom.widget
org.mozilla.fennec_aurora
org.mozilla.fenix
org.mozilla.fenix.nightly
org.mozilla.firefox
org.mozilla.firefox_beta
org.mozilla.focus
org.schabi.newpipe
org.telegram.messenger
org.telegram.multi
org.telegram.plus
org.thunderdog.challegram
org.torproject.android
org.torproject.torbrowser_alpha
org.wikipedia
org.xbmc.kodi
pl.zdunex25.updater
tv.twitch.android.app
tw.com.gamer.android.activecenter
videodownloader.downloadvideo.downloader
uk.co.bbc.learningenglish
com.ted.android
de.danoeh.antennapod
com.kiwibrowser.browser
nekox.messenger
com.nextcloud.client
com.aurora.store
com.aurora.adroid
chat.simplex.app
im.vector.app
network.loki.messenger
eu.siacs.conversations
xyz.nextalone.nagram
de.danoeh.antennapod
net.programmierecke.radiodroid2
im.fdx.v2ex
ml.docilealligator.infinityforreddit
com.bytemyth.ama
app.vanadium.browser
com.cakewallet.cake_wallet
org.purplei2p.i2pd
dk.tacit.android.foldersync.lite
com.nononsenseapps.feeder
com.m2049r.xmrwallet
com.paypal.android.p2pmobile
com.google.android.apps.googlevoice
com.readdle.spark
org.torproject.torbrowser
com.deepl.mobiletranslator
com.microsoft.bing
com.keylesspalace.tusky
com.ottplay.ottplay
ru.iptvremote.android.iptv.pro
jp.naver.line.android
com.xmflsct.app.tooot
com.forem.android
app.revanced.android.youtube
app.rvx.android.youtube
app.rvx.android.apps.youtube.music
com.mgoogle.android.gms
com.pionex.client
vip.mytokenpocket
im.token.app
com.linekong.mars24
com.feixiaohao
com.aicoin.appandroid
com.binance.dev
com.kraken.trade
com.okinc.okex.gp
com.authy.authy
air.com.rosettastone.mobile.CoursePlayer
com.blizzard.bma
com.amazon.kindle
com.google.android.apps.fitness
net.tsapps.appsales
com.wemesh.android
com.google.android.apps.googleassistant
allen.town.focus.reader
me.hyliu.fluent_reader_lite
com.aljazeera.mobile
com.ft.news
de.marmaro.krt.ffupdater
myradio.radio.fmradio.liveradio.radiostation
com.google.earth
eu.kanade.tachiyomi.j2k
com.audials
com.microsoft.skydrive
com.mb.android.tg
com.melodis.midomiMusicIdentifier.freemium
com.foxnews.android
ch.threema.app
com.briarproject.briar.android
foundation.e.apps
com.valvesoftware.android.steam.friendsui
com.imback.yeetalk
so.onekey.app.wallet
com.xc3fff0e.xmanager
meditofoundation.medito
com.picol.client
com.streetwriters.notesnook
shanghai.panewsApp.com
org.coursera.android
com.positron_it.zlib
com.blizzard.messenger
com.javdb.javrocket
com.picacomic.fregata
com.fxl.chacha
me.proton.android.drive
com.lastpass.lpandroid
com.tradingview.tradingviewapp
com.deviantart.android.damobile
com.fusionmedia.investing
com.ewa.ewaapp
com.duolingo
com.hellotalk
io.github.huskydg.magisk
com.jsy.xpgbox
com.hostloc.app.hostloc
com.dena.pokota
com.vitorpamplona.amethyst
com.zhiliaoapp.musically
us.spotco.fennec_dos
com.fongmi.android.tv
com.pocketprep.android.itcybersecurity
com.cloudtv
com.glassdoor.app
com.indeed.android.jobsearch
com.linkedin.android
com.github.tvbox.osc.bh
com.example.douban
com.sipnetic.app
com.microsoft.rdc.androidx
org.zwanoo.android.speedtest
com.sonelli.juicessh
com.scmp.newspulse
org.lsposed.manager
mnn.Android
com.thomsonretuers.reuters
com.guardian
com.ttxapps.onesyncv2
org.fcitx.fcitx5.android.updater
com.instagram.barcelona
com.deniscerri.ytdl
jp.pokemon.pokemonsleep
com.github.android
com.openai.chatgpt
mega.privacy.android.app
com.taptap.global
tw.com.gamer.android.animad
com.microsoft.copilot
com.google.android.apps.aiwallpapers
ai.x.grok
com.google.android.apps.weather
com.metrolist.music
com.google.android.apps.youtube.creator

================================================
FILE: app/src/main/assets/yacd.version.txt
================================================
3

================================================
FILE: app/src/main/java/com/github/shadowsocks/plugin/Utils.kt
================================================
@file:JvmName("Utils")

package com.github.shadowsocks.plugin

import android.os.Parcelable
import kotlinx.parcelize.Parcelize

@Parcelize
class Empty : Parcelable

================================================
FILE: app/src/main/java/com/github/shadowsocks/plugin/fragment/AlertDialogFragment.kt
================================================
package com.github.shadowsocks.plugin.fragment

import android.app.Activity
import android.content.DialogInterface
import android.os.Bundle
import android.os.Parcelable
import androidx.appcompat.app.AlertDialog
import androidx.appcompat.app.AppCompatDialogFragment
import androidx.fragment.app.Fragment
import androidx.fragment.app.setFragmentResult
import androidx.fragment.app.setFragmentResultListener
import com.google.android.material.dialog.MaterialAlertDialogBuilder

/**
 * Based on: https://android.googlesource.com/platform/
packages/apps/ExactCalculator/+/8c43f06/src/com/android/calculator2/AlertDialogFragment.java
 */
abstract class AlertDialogFragment<Arg : Parcelable, Ret : Parcelable?> :
    AppCompatDialogFragment(), DialogInterface.OnClickListener {
    companion object {
        private const val KEY_RESULT = "result"
        private const val KEY_ARG = "arg"
        private const val KEY_RET = "ret"
        private const val KEY_WHICH = "which"

        fun <Ret : Parcelable> setResultListener(fragment: Fragment, requestKey: String,
                                                 listener: (Int, Ret?) -> Unit) {
            fragment.setFragmentResultListener(requestKey) { _, bundle ->
                listener(bundle.getInt(KEY_WHICH, Activity.RESULT_CANCELED), bundle.getParcelable(KEY_RET))
            }
        }
        inline fun <reified T : AlertDialogFragment<*, Ret>, Ret : Parcelable?> setResultListener(
            fragment: Fragment, noinline listener: (Int, Ret?) -> Unit) =
            setResultListener(fragment, T::class.java.name, listener)
    }
    protected abstract fun AlertDialog.Builder.prepare(listener: DialogInterface.OnClickListener)

    private val resultKey get() = requireArguments().getString(KEY_RESULT)
    protected val arg by lazy { requireArguments().getParcelable<Arg>(KEY_ARG)!! }
    protected open fun ret(which: Int): Ret? = null

    private fun args() = arguments ?: Bundle().also { arguments = it }
    fun arg(arg: Arg) = args().putParcelable(KEY_ARG, arg)
    fun key(resultKey: String = javaClass.name) = args().putString(KEY_RESULT, resultKey)

    override fun onCreateDialog(savedInstanceState: Bundle?): AlertDialog =
        MaterialAlertDialogBuilder(requireContext()).also { it.prepare(this) }.create()

    override fun onClick(dialog: DialogInterface?, which: Int) {
        setFragmentResult(resultKey ?: return, Bundle().apply {
            putInt(KEY_WHICH, which)
            putParcelable(KEY_RET, ret(which) ?: return@apply)
        })
    }

    override fun onDismiss(dialog: DialogInterface) {
        super.onDismiss(dialog)
        onClick(null, Activity.RESULT_CANCELED)
    }
}


================================================
FILE: app/src/main/java/io/nekohasekai/sagernet/BootReceiver.kt
================================================
package io.nekohasekai.sagernet

import android.content.BroadcastReceiver
import android.content.ComponentName
import android.content.Context
import android.content.Intent
import android.content.pm.PackageManager
import android.os.Build
import io.nekohasekai.sagernet.bg.SubscriptionUpdater
import io.nekohasekai.sagernet.database.DataStore
import io.nekohasekai.sagernet.ktx.app
import io.nekohasekai.sagernet.ktx.runOnDefaultDispatcher

class BootReceiver : BroadcastReceiver() {
    companion object {
        private val componentName by lazy { ComponentName(app, BootReceiver::class.java) }
        var enabled: Boolean
            get() = app.packageManager.getComponentEnabledSetting(componentName) == PackageManager.COMPONENT_ENABLED_STATE_ENABLED
            set(value) = app.packageManager.setComponentEnabledSetting(
                componentName, if (value) PackageManager.COMPONENT_ENABLED_STATE_ENABLED
                else PackageManager.COMPONENT_ENABLED_STATE_DISABLED, PackageManager.DONT_KILL_APP
            )
    }

    override fun onReceive(context: Context, intent: Intent) {
        runOnDefaultDispatcher {
            SubscriptionUpdater.reconfigureUpdater()
        }

        if (!DataStore.persistAcrossReboot) {   // sanity check
            enabled = false
            return
        }

        val doStart = when (intent.action) {
            Intent.ACTION_LOCKED_BOOT_COMPLETED -> false // DataStore.directBootAware
            else -> Build.VERSION.SDK_INT < 24 || SagerNet.user.isUserUnlocked
        } && DataStore.selectedProxy > 0

        if (doStart) SagerNet.startService()
    }
}


================================================
FILE: app/src/main/java/io/nekohasekai/sagernet/Constants.kt
================================================
package io.nekohasekai.sagernet

const val CONNECTION_TEST_URL = "http://cp.cloudflare.com/"

object Key {

    const val DB_PUBLIC = "configuration.db"
    const val DB_PROFILE = "sager_net.db"

    const val PERSIST_ACROSS_REBOOT = "isAutoConnect"

    const val APP_EXPERT = "isExpert"
    const val APP_THEME = "appTheme"
    const val NIGHT_THEME = "nightTheme"
    const val SERVICE_MODE = "serviceMode"
    const val MODE_VPN = "vpn"
    const val MODE_PROXY = "proxy"

    const val GLOBAL_CUSTOM_CONFIG = "globalCustomConfig"

    const val REMOTE_DNS = "remoteDns"
    const val DIRECT_DNS = "directDns"
    const val ENABLE_DNS_ROUTING = "enableDnsRouting"
    const val ENABLE_FAKEDNS = "enableFakeDns"

    const val IPV6_MODE = "ipv6Mode"

    const val PROXY_APPS = "proxyApps"
    const val BYPASS_MODE = "bypassMode"
    const val INDIVIDUAL = "individual"
    const val METERED_NETWORK = "meteredNetwork"

    const val TRAFFIC_SNIFFING = "trafficSniffing"
    const val RESOLVE_DESTINATION = "resolveDestination"

    const val BYPASS_LAN = "bypassLan"
    const val BYPASS_LAN_IN_CORE = "bypassLanInCore"

    const val MIXED_PORT = "mixedPort"
    const val ALLOW_ACCESS = "allowAccess"
    const val SPEED_INTERVAL = "speedInterval"
    const val SHOW_DIRECT_SPEED = "showDirectSpeed"

    const val APPEND_HTTP_PROXY = "appendHttpProxy"

    const val CONNECTION_TEST_URL = "connectionTestURL"

    const val NETWORK_CHANGE_RESET_CONNECTIONS = "networkChangeResetConnections"
    const val WAKE_RESET_CONNECTIONS = "wakeResetConnections"
    const val RULES_PROVIDER = "rulesProvider"
    const val LOG_LEVEL = "logLevel"
    const val LOG_BUF_SIZE = "logBufSize"
    const val MTU = "mtu"
    const val ALWAYS_SHOW_ADDRESS = "alwaysShowAddress"

    // Protocol Settings
    const val GLOBAL_ALLOW_INSECURE = "globalAllowInsecure"

    const val ACQUIRE_WAKE_LOCK = "acquireWakeLock"
    const val SHOW_BOTTOM_BAR = "showBottomBar"

    const val ALLOW_INSECURE_ON_REQUEST = "allowInsecureOnRequest"

    const val TUN_IMPLEMENTATION = "tunImplementation"
    const val PROFILE_TRAFFIC_STATISTICS = "profileTrafficStatistics"

    const val PROFILE_DIRTY = "profileDirty"
    const val PROFILE_ID = "profileId"
    const val PROFILE_NAME = "profileName"
    const val PROFILE_GROUP = "profileGroup"
    const val PROFILE_CURRENT = "profileCurrent"

    const val SERVER_ADDRESS = "serverAddress"
    const val SERVER_PORT = "serverPort"
    const val SERVER_USERNAME = "serverUsername"
    const val SERVER_PASSWORD = "serverPassword"
    const val SERVER_METHOD = "serverMethod"
    const val SERVER_PASSWORD1 = "serverPassword1"

    const val PROTOCOL_VERSION = "protocolVersion"

    const val SERVER_PROTOCOL = "serverProtocol"
    const val SERVER_OBFS = "serverObfs"

    const val SERVER_NETWORK = "serverNetwork"
    const val SERVER_HOST = "serverHost"
    const val SERVER_PATH = "serverPath"
    const val SERVER_SNI = "serverSNI"
    const val SERVER_ENCRYPTION = "serverEncryption"
    const val SERVER_ALPN = "serverALPN"
    const val SERVER_CERTIFICATES = "serverCertificates"
    const val SERVER_MTU = "serverMTU"

    const val SERVER_CONFIG = "serverConfig"
    const val SERVER_CUSTOM = "serverCustom"
    const val SERVER_CUSTOM_OUTBOUND = "serverCustomOutbound"

    const val SERVER_SECURITY_CATEGORY = "serverSecurityCategory"
    const val SERVER_TLS_CAMOUFLAGE_CATEGORY = "serverTlsCamouflageCategory"
    const val SERVER_ECH_CATEORY = "serverECHCategory"
    const val SERVER_WS_CATEGORY = "serverWsCategory"
    const val SERVER_SS_CATEGORY = "serverSsCategory"
    const val SERVER_HEADERS = "serverHeaders"
    const val SERVER_ALLOW_INSECURE = "serverAllowInsecure"

    const val SERVER_AUTH_TYPE = "serverAuthType"
    const val SERVER_UPLOAD_SPEED = "serverUploadSpeed"
    const val SERVER_DOWNLOAD_SPEED = "serverDownloadSpeed"
    const val SERVER_STREAM_RECEIVE_WINDOW = "serverStreamReceiveWindow"
    const val SERVER_CONNECTION_RECEIVE_WINDOW = "serverConnectionReceiveWindow"
    const val SERVER_DISABLE_MTU_DISCOVERY = "serverDisableMtuDiscovery"
    const val SERVER_HOP_INTERVAL = "hopInterval"

    const val SERVER_PRIVATE_KEY = "serverPrivateKey"
    const val SERVER_INSECURE_CONCURRENCY = "serverInsecureConcurrency"

    const val SERVER_UDP_RELAY_MODE = "serverUDPRelayMode"
    const val SERVER_CONGESTION_CONTROLLER = "serverCongestionController"
    const val SERVER_DISABLE_SNI = "serverDisableSNI"
    const val SERVER_REDUCE_RTT = "serverReduceRTT"

    const val ROUTE_NAME = "routeName"
    const val ROUTE_DOMAIN = "routeDomain"
    const val ROUTE_IP = "routeIP"
    const val ROUTE_PORT = "routePort"
    const val ROUTE_SOURCE_PORT = "routeSourcePort"
    const val ROUTE_NETWORK = "routeNetwork"
    const val ROUTE_SOURCE = "routeSource"
    const val ROUTE_PROTOCOL = "routeProtocol"
    const val ROUTE_OUTBOUND = "routeOutbound"
    const val ROUTE_PACKAGES = "routePackages"

    const val GROUP_NAME = "groupName"
    const val GROUP_TYPE = "groupType"
    const val GROUP_ORDER = "groupOrder"
    const val GROUP_IS_SELECTOR = "groupIsSelector"
    const val GROUP_FRONT_PROXY = "groupFrontProxy"
    const val GROUP_LANDING_PROXY = "groupLandingProxy"

    const val GROUP_SUBSCRIPTION = "groupSubscription"
    const val SUBSCRIPTION_LINK = "subscriptionLink"
    const val SUBSCRIPTION_FORCE_RESOLVE = "subscriptionForceResolve"
    const val SUBSCRIPTION_DEDUPLICATION = "subscriptionDeduplication"
    const val SUBSCRIPTION_UPDATE = "subscriptionUpdate"
    const val SUBSCRIPTION_UPDATE_WHEN_CONNECTED_ONLY = "subscriptionUpdateWhenConnectedOnly"
    const val SUBSCRIPTION_USER_AGENT = "subscriptionUserAgent"
    const val SUBSCRIPTION_AUTO_UPDATE = "subscriptionAutoUpdate"
    const val SUBSCRIPTION_AUTO_UPDATE_DELAY = "subscriptionAutoUpdateDelay"

    //

    const val APP_TLS_VERSION = "appTLSVersion"
    const val ENABLE_CLASH_API = "enableClashAPI"
}

object TunImplementation {
    const val GVISOR = 0
    const val SYSTEM = 1
    const val MIXED = 2
}

object IPv6Mode {
    const val DISABLE = 0
    const val ENABLE = 1
    const val PREFER = 2
    const val ONLY = 3
}

object GroupType {
    const val BASIC = 0
    const val SUBSCRIPTION = 1
}

object GroupOrder {
    const val ORIGIN = 0
    const val BY_NAME = 1
    const val BY_DELAY = 2
}

object Action {
    const val SERVICE = "io.nekohasekai.sagernet.SERVICE"
    const val CLOSE = "io.nekohasekai.sagernet.CLOSE"
    const val RELOAD = "io.nekohasekai.sagernet.RELOAD"

    // const val SWITCH_WAKE_LOCK = "io.nekohasekai.sagernet.SWITCH_WAKELOCK"
    const val RESET_UPSTREAM_CONNECTIONS = "moe.nb4a.RESET_UPSTREAM_CONNECTIONS"
}


================================================
FILE: app/src/main/java/io/nekohasekai/sagernet/QuickToggleShortcut.kt
================================================
/*******************************************************************************
 *                                                                             *
 *  Copyright (C) 2017 by Max Lv <max.c.lv@gmail.com>                          *
 *  Copyright (C) 2017 by Mygod Studio <contact-shadowsocks-android@mygod.be>  *
 *                                                                             *
 *  This program is free software: you can redistribute it and/or modify       *
 *  it under the terms of the GNU General Public License as published by       *
 *  the Free Software Foundation, either version 3 of the License, or          *
 *  (at your option) any later version.                                        *
 *                                                                             *
 *  This program is distributed in the hope that it will be useful,            *
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of             *
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the              *
 *  GNU General Public License for more details.                               *
 *                                                                             *
 *  You should have received a copy of the GNU General Public License          *
 *  along with this program. If not, see <http://www.gnu.org/licenses/>.       *
 *                                                                             *
 *******************************************************************************/

package io.nekohasekai.sagernet

import android.app.Activity
import android.content.Intent
import android.content.pm.ShortcutManager
import android.os.Build
import android.os.Bundle
import androidx.core.content.getSystemService
import androidx.core.content.pm.ShortcutInfoCompat
import androidx.core.content.pm.ShortcutManagerCompat
import androidx.core.graphics.drawable.IconCompat
import io.nekohasekai.sagernet.aidl.ISagerNetService
import io.nekohasekai.sagernet.bg.BaseService
import io.nekohasekai.sagernet.bg.SagerConnection
import io.nekohasekai.sagernet.database.DataStore

@Suppress("DEPRECATION")
class QuickToggleShortcut : Activity(), SagerConnection.Callback {
    private val connection = SagerConnection(SagerConnection.CONNECTION_ID_SHORTCUT)
    private var profileId = -1L

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        if (intent.action == Intent.ACTION_CREATE_SHORTCUT) {
            setResult(RESULT_OK, ShortcutManagerCompat.createShortcutResultIntent(this,
                ShortcutInfoCompat.Builder(this, "toggle")
                    .setIntent(Intent(this,
                        QuickToggleShortcut::class.java).setAction(Intent.ACTION_MAIN))
                    .setIcon(IconCompat.createWithResource(this,
                        R.drawable.ic_qu_shadowsocks_launcher))
                    .setShortLabel(getString(R.string.quick_toggle))
                    .build()))
            finish()
        } else {
            profileId = intent.getLongExtra("profile", -1L)
            connection.connect(this, this)
            if (Build.VERSION.SDK_INT >= 25) {
                getSystemService<ShortcutManager>()!!.reportShortcutUsed(if (profileId >= 0) "shortcut-profile-$profileId" else "toggle")
            }
        }
    }

    override fun onServiceConnected(service: ISagerNetService) {
        val state = BaseService.State.values()[service.state]
        when {
            state.canStop -> {
                if (profileId == DataStore.selectedProxy || profileId == -1L) {
                    SagerNet.stopService()
                } else {
                    DataStore.selectedProxy = profileId
                    SagerNet.reloadService()
                }
            }
            state == BaseService.State.Stopped -> {
                if (profileId >= 0L) DataStore.selectedProxy = profileId
                SagerNet.startService()
            }
        }
        finish()
    }

    override fun stateChanged(state: BaseService.State, profileName: String?, msg: String?) {}

    override fun onDestroy() {
        connection.disconnect(this)
        super.onDestroy()
    }
}


================================================
FILE: app/src/main/java/io/nekohasekai/sagernet/SagerNet.kt
================================================
package io.nekohasekai.sagernet

import android.annotation.SuppressLint
import android.app.*
import android.content.ClipData
import android.content.ClipboardManager
import android.content.Context
import android.content.Intent
import android.content.res.Configuration
import android.net.ConnectivityManager
import android.net.Network
import android.os.Build
import android.os.PowerManager
import android.os.StrictMode
import android.os.UserManager
import androidx.annotation.RequiresApi
import androidx.core.content.ContextCompat
import androidx.core.content.getSystemService
import go.Seq
import io.nekohasekai.sagernet.bg.SagerConnection
import io.nekohasekai.sagernet.database.DataStore
import io.nekohasekai.sagernet.ktx.Logs
import io.nekohasekai.sagernet.ktx.isOss
import io.nekohasekai.sagernet.ktx.isPreview
import io.nekohasekai.sagernet.ktx.runOnDefaultDispatcher
import io.nekohasekai.sagernet.ui.MainActivity
import io.nekohasekai.sagernet.utils.*
import kotlinx.coroutines.DEBUG_PROPERTY_NAME
import kotlinx.coroutines.DEBUG_PROPERTY_VALUE_ON
import libcore.Libcore
import moe.matsuri.nb4a.NativeInterface
import moe.matsuri.nb4a.net.LocalResolverImpl
import moe.matsuri.nb4a.utils.JavaUtil
import moe.matsuri.nb4a.utils.cleanWebview
import java.io.File
import androidx.work.Configuration as WorkConfiguration

class SagerNet : Application(),
    WorkConfiguration.Provider {

    override fun attachBaseContext(base: Context) {
        super.attachBaseContext(base)

        application = this
    }

    private val nativeInterface = NativeInterface()

    val externalAssets: File by lazy { getExternalFilesDir(null) ?: filesDir }
    val process: String = JavaUtil.getProcessName()
    private val isMainProcess = process == BuildConfig.APPLICATION_ID
    val isBgProcess = process.endsWith(":bg")

    override fun onCreate() {
        super.onCreate()

        Thread.setDefaultUncaughtExceptionHandler(CrashHandler)

        if (isMainProcess || isBgProcess) {
            externalAssets.mkdirs()
            Seq.setContext(this)
            Libcore.initCore(
                process,
                cacheDir.absolutePath + "/",
                filesDir.absolutePath + "/",
                externalAssets.absolutePath + "/",
                DataStore.logBufSize,
                DataStore.logLevel > 0,
                nativeInterface, nativeInterface, LocalResolverImpl
            )

            // fix multi process issue in Android 9+
            JavaUtil.handleWebviewDir(this)

            runOnDefaultDispatcher {
                PackageCache.register()
                cleanWebview()
            }
        }

        if (isMainProcess) {
            Theme.apply(this)
            Theme.applyNightTheme()
            runOnDefaultDispatcher {
                DefaultNetworkListener.start(this) {
                    underlyingNetwork = it
                }

                updateNotificationChannels()
            }
        }

        if (BuildConfig.DEBUG) {
            System.setProperty(DEBUG_PROPERTY_NAME, DEBUG_PROPERTY_VALUE_ON)
            StrictMode.setVmPolicy(
                StrictMode.VmPolicy.Builder()
                    .detectLeakedSqlLiteObjects()
                    .detectLeakedClosableObjects()
                    .detectLeakedRegistrationObjects()
                    .penaltyLog()
                    .build()
            )
        }
    }

    override fun onConfigurationChanged(newConfig: Configuration) {
        super.onConfigurationChanged(newConfig)
        updateNotificationChannels()
    }

    override fun getWorkManagerConfiguration(): WorkConfiguration {
        return WorkConfiguration.Builder()
            .setDefaultProcessName("${BuildConfig.APPLICATION_ID}:bg")
            .build()
    }

    override fun onTrimMemory(level: Int) {
        super.onTrimMemory(level)

        Libcore.forceGc()
    }

    @SuppressLint("InlinedApi")
    companion object {

        lateinit var application: SagerNet

        val isTv by lazy {
            uiMode.currentModeType == Configuration.UI_MODE_TYPE_TELEVISION
        }

        val configureIntent: (Context) -> PendingIntent by lazy {
            {
                PendingIntent.getActivity(
                    it,
                    0,
                    Intent(
                        application, MainActivity::class.java
                    ).setFlags(Intent.FLAG_ACTIVITY_REORDER_TO_FRONT),
                    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) PendingIntent.FLAG_IMMUTABLE else 0
                )
            }
        }
        val activity by lazy { application.getSystemService<ActivityManager>()!! }
        val clipboard by lazy { application.getSystemService<ClipboardManager>()!! }
        val connectivity by lazy { application.getSystemService<ConnectivityManager>()!! }
        val notification by lazy { application.getSystemService<NotificationManager>()!! }
        val user by lazy { application.getSystemService<UserManager>()!! }
        val uiMode by lazy { application.getSystemService<UiModeManager>()!! }
        val power by lazy { application.getSystemService<PowerManager>()!! }

        fun getClipboardText(): String {
            return clipboard.primaryClip?.takeIf { it.itemCount > 0 }
                ?.getItemAt(0)?.text?.toString() ?: ""
        }

        fun trySetPrimaryClip(clip: String) = try {
            clipboard.setPrimaryClip(ClipData.newPlainText(null, clip))
            true
        } catch (e: RuntimeException) {
            Logs.w(e)
            false
        }

        fun updateNotificationChannels() {
            if (Build.VERSION.SDK_INT >= 26) @RequiresApi(26) {
                notification.createNotificationChannels(
                    listOf(
                        NotificationChannel(
                            "service-vpn",
                            application.getText(R.string.service_vpn),
                            if (Build.VERSION.SDK_INT >= 28) NotificationManager.IMPORTANCE_MIN
                            else NotificationManager.IMPORTANCE_LOW
                        ),   // #1355
                        NotificationChannel(
                            "service-proxy",
                            application.getText(R.string.service_proxy),
                            NotificationManager.IMPORTANCE_LOW
                        ), NotificationChannel(
                            "service-subscription",
                            application.getText(R.string.service_subscription),
                            NotificationManager.IMPORTANCE_DEFAULT
                        ), NotificationChannel(
                            "connection-test",
                            application.getText(R.string.connection_test),
                            NotificationManager.IMPORTANCE_DEFAULT
                        )
                    )
                )
            }
        }

        fun startService() = ContextCompat.startForegroundService(
            application, Intent(application, SagerConnection.serviceClass)
        )

        fun reloadService() =
            application.sendBroadcast(Intent(Action.RELOAD).setPackage(application.packageName))

        fun stopService() =
            application.sendBroadcast(Intent(Action.CLOSE).setPackage(application.packageName))

        var underlyingNetwork: Network? = null

        var appVersionNameForDisplay = {
            var n = BuildConfig.VERSION_NAME
            if (isPreview) {
                n += " " + BuildConfig.PRE_VERSION_NAME
            } else if (!isOss) {
                n += " ${BuildConfig.FLAVOR}"
            }
            if (BuildConfig.DEBUG) {
                n += " DEBUG"
            }
            n
        }()
    }

}


================================================
FILE: app/src/main/java/io/nekohasekai/sagernet/aidl/SpeedDisplayData.kt
================================================
package io.nekohasekai.sagernet.aidl

import android.os.Parcelable
import kotlinx.parcelize.Parcelize

@Parcelize
data class SpeedDisplayData(
    // Bytes per second
    var txRateProxy: Long = 0L,
    var rxRateProxy: Long = 0L,
    var txRateDirect: Long = 0L,
    var rxRateDirect: Long = 0L,

    // Bytes for the current session
    // Outbound "bypass" usage is not counted
    var txTotal: Long = 0L,
    var rxTotal: Long = 0L,
) : Parcelable


================================================
FILE: app/src/main/java/io/nekohasekai/sagernet/aidl/TrafficData.kt
================================================
package io.nekohasekai.sagernet.aidl

import android.os.Parcelable
import kotlinx.parcelize.Parcelize

@Parcelize
data class TrafficData(
    var id: Long = 0L,
    var tx: Long = 0L,
    var rx: Long = 0L,
) : Parcelable


================================================
FILE: app/src/main/java/io/nekohasekai/sagernet/bg/AbstractInstance.kt
================================================
package io.nekohasekai.sagernet.bg

import java.io.Closeable

interface AbstractInstance : Closeable {

    fun launch()

}

================================================
FILE: app/src/main/java/io/nekohasekai/sagernet/bg/BaseService.kt
================================================
package io.nekohasekai.sagernet.bg

import android.app.Service
import android.content.Context
import android.content.Intent
import android.content.IntentFilter
import android.os.*
import android.widget.Toast
import io.nekohasekai.sagernet.Action
import io.nekohasekai.sagernet.BootReceiver
import io.nekohasekai.sagernet.R
import io.nekohasekai.sagernet.SagerNet
import io.nekohasekai.sagernet.aidl.ISagerNetService
import io.nekohasekai.sagernet.aidl.ISagerNetServiceCallback
import io.nekohasekai.sagernet.bg.proto.ProxyInstance
import io.nekohasekai.sagernet.database.DataStore
import io.nekohasekai.sagernet.database.SagerDatabase
import io.nekohasekai.sagernet.ktx.*
import io.nekohasekai.sagernet.plugin.PluginManager
import io.nekohasekai.sagernet.utils.DefaultNetworkListener
import kotlinx.coroutines.*
import kotlinx.coroutines.sync.Mutex
import kotlinx.coroutines.sync.withLock
import libcore.Libcore
import moe.matsuri.nb4a.Protocols
import moe.matsuri.nb4a.utils.Util
import java.net.UnknownHostException

class BaseService {

    enum class State(
        val canStop: Boolean = false,
        val started: Boolean = false,
        val connected: Boolean = false,
    ) {
        /**
         * Idle state is only used by UI and will never be returned by BaseService.
         */
        Idle, Connecting(true, true, false), Connected(true, true, true), Stopping, Stopped,
    }

    interface ExpectedException

    class Data internal constructor(private val service: Interface) {
        var state = State.Stopped
        var proxy: ProxyInstance? = null
        var notification: ServiceNotification? = null

        val receiver = broadcastReceiver { ctx, intent ->
            when (intent.action) {
                Intent.ACTION_SHUTDOWN -> service.persistStats()
                Action.RELOAD -> service.reload()
                // Action.SWITCH_WAKE_LOCK -> runOnDefaultDispatcher { service.switchWakeLock() }
                PowerManager.ACTION_DEVICE_IDLE_MODE_CHANGED -> {
                    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
                        if (SagerNet.power.isDeviceIdleMode) {
                            proxy?.box?.sleep()
                        } else {
                            proxy?.box?.wake()
                            if (DataStore.wakeResetConnections) {
                                Libcore.resetAllConnections(true)
                            }
                        }
                    }
                }

                Action.RESET_UPSTREAM_CONNECTIONS -> runOnDefaultDispatcher {
                    Libcore.resetAllConnections(true)
                    runOnMainDispatcher {
                        Util.collapseStatusBar(ctx)
                        Toast.makeText(ctx, "Reset upstream connections done", Toast.LENGTH_SHORT)
                            .show()
                    }
                }

                else -> service.stopRunner()
            }
        }
        var closeReceiverRegistered = false

        val binder = Binder(this)
        var connectingJob: Job? = null

        fun changeState(s: State, msg: String? = null) {
            if (state == s && msg == null) return
            state = s
            DataStore.serviceState = s
            binder.stateChanged(s, msg)
        }
    }

    class Binder(private var data: Data? = null) : ISagerNetService.Stub(), CoroutineScope,
        AutoCloseable {
        private val callbacks = object : RemoteCallbackList<ISagerNetServiceCallback>() {
            override fun onCallbackDied(callback: ISagerNetServiceCallback?, cookie: Any?) {
                super.onCallbackDied(callback, cookie)
            }
        }

        val callbackIdMap = mutableMapOf<ISagerNetServiceCallback, Int>()

        override val coroutineContext = Dispatchers.Main.immediate + Job()

        override fun getState(): Int = (data?.state ?: State.Idle).ordinal
        override fun getProfileName(): String = data?.proxy?.displayProfileName ?: "Idle"

        override fun registerCallback(cb: ISagerNetServiceCallback, id: Int) {
            if (id == SagerConnection.CONNECTION_ID_RESTART_BG) {
                Runtime.getRuntime().exit(0)
                return
            }
            if (!callbackIdMap.contains(cb)) {
                callbacks.register(cb)
            }
            callbackIdMap[cb] = id
        }

        private val broadcastMutex = Mutex()

        suspend fun broadcast(work: (ISagerNetServiceCallback) -> Unit) {
            broadcastMutex.withLock {
                val count = callbacks.beginBroadcast()
                try {
                    repeat(count) {
                        try {
                            work(callbacks.getBroadcastItem(it))
                        } catch (_: RemoteException) {
                        } catch (_: Exception) {
                        }
                    }
                } finally {
                    callbacks.finishBroadcast()
                }
            }
        }

        override fun unregisterCallback(cb: ISagerNetServiceCallback) {
            callbackIdMap.remove(cb)
            callbacks.unregister(cb)
        }

        override fun urlTest(): Int {
            if (data?.proxy?.box == null) {
                error("core not started")
            }
            try {
                return Libcore.urlTest(
                    data!!.proxy!!.box, DataStore.connectionTestURL, 3000
                )
            } catch (e: Exception) {
                error(Protocols.genFriendlyMsg(e.readableMessage))
            }
        }

        fun stateChanged(s: State, msg: String?) = launch {
            val profileName = profileName
            broadcast { it.stateChanged(s.ordinal, profileName, msg) }
        }

        fun missingPlugin(pluginName: String) = launch {
            val profileName = profileName
            broadcast { it.missingPlugin(profileName, pluginName) }
        }

        override fun close() {
            callbacks.kill()
            cancel()
            data = null
        }
    }

    interface Interface {
        val data: Data
        val tag: String
        fun createNotification(profileName: String): ServiceNotification

        fun onBind(intent: Intent): IBinder? =
            if (intent.action == Action.SERVICE) data.binder else null

        fun reload() {
            if (DataStore.selectedProxy == 0L) {
                stopRunner(false, (this as Context).getString(R.string.profile_empty))
            }
            if (canReloadSelector()) {
                val ent = SagerDatabase.proxyDao.getById(DataStore.selectedProxy)
                val tag = data.proxy!!.config.profileTagMap[ent?.id] ?: ""
                if (tag.isNotBlank() && ent != null) {
                    // select from GUI
                    data.proxy!!.box.selectOutbound(tag)
                    // or select from webui
                    // => selector_OnProxySelected
                }
                return
            }
            val s = data.state
            when {
                s == State.Stopped -> startRunner()
                s.canStop -> stopRunner(true)
                else -> Logs.w("Illegal state $s when invoking use")
            }
        }

        fun canReloadSelector(): Boolean {
            if ((data.proxy?.config?.selectorGroupId ?: -1L) < 0) return false
            val ent = SagerDatabase.proxyDao.getById(DataStore.selectedProxy) ?: return false
            val tmpBox = ProxyInstance(ent)
            tmpBox.buildConfigTmp()
            if (tmpBox.lastSelectorGroupId == data.proxy?.lastSelectorGroupId) {
                return true
            }
            return false
        }

        suspend fun startProcesses() {
            data.proxy!!.launch()
        }

        fun startRunner() {
            this as Context
            if (Build.VERSION.SDK_INT >= 26) startForegroundService(Intent(this, javaClass))
            else startService(Intent(this, javaClass))
        }

        fun killProcesses() {
            data.proxy?.close()
            wakeLock?.apply {
                release()
                wakeLock = null
            }
            runOnDefaultDispatcher {
                DefaultNetworkListener.stop(this)
            }
        }

        fun stopRunner(restart: Boolean = false, msg: String? = null) {
            DataStore.baseService = null
            DataStore.vpnService = null

            if (data.state == State.Stopping) return
            data.notification?.destroy()
            data.notification = null
            this as Service

            data.changeState(State.Stopping)

            runOnMainDispatcher {
                data.connectingJob?.cancelAndJoin() // ensure stop connecting first
                // we use a coroutineScope here to allow clean-up in parallel
                coroutineScope {
                    killProcesses()
                    val data = data
                    if (data.closeReceiverRegistered) {
                        unregisterReceiver(data.receiver)
                        data.closeReceiverRegistered = false
                    }
                    data.proxy = null
                }

                // change the state
                data.changeState(State.Stopped, msg)
                // stop the service if nothing has bound to it
                if (restart) startRunner() else {
                    stopSelf()
                }
            }
        }

        fun persistStats() {
            // TODO NEW save app stats?
        }

        // networks
        var upstreamInterfaceName: String?

        suspend fun preInit() {
            DefaultNetworkListener.start(this) {
                SagerNet.connectivity.getLinkProperties(it)?.also { link ->
                    SagerNet.underlyingNetwork = it
                    DataStore.vpnService?.updateUnderlyingNetwork()
                    //
                    val oldName = upstreamInterfaceName
                    if (oldName != link.interfaceName) {
                        upstreamInterfaceName = link.interfaceName
                    }
                    if (oldName != null && upstreamInterfaceName != null && oldName != upstreamInterfaceName) {
                        Logs.d("Network changed: $oldName -> $upstreamInterfaceName")
                        if (DataStore.networkChangeResetConnections) {
                            Libcore.resetAllConnections(true)
                        }
                    }
                }
            }
        }

        var wakeLock: PowerManager.WakeLock?
        fun acquireWakeLock()

        suspend fun lateInit() {
            wakeLock?.apply {
                release()
                wakeLock = null
            }

            if (DataStore.acquireWakeLock) {
                acquireWakeLock()
                data.notification?.postNotificationWakeLockStatus(true)
            } else {
                data.notification?.postNotificationWakeLockStatus(false)
            }
        }

        fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
            DataStore.baseService = this

            val data = data
            if (data.state != State.Stopped) return Service.START_NOT_STICKY
            val profile = SagerDatabase.proxyDao.getById(DataStore.selectedProxy)
            this as Context
            if (profile == null) { // gracefully shutdown: https://stackoverflow.com/q/47337857/2245107
                data.notification = createNotification("")
                stopRunner(false, getString(R.string.profile_empty))
                return Service.START_NOT_STICKY
            }

            val proxy = ProxyInstance(profile, this)
            data.proxy = proxy
            BootReceiver.enabled = DataStore.persistAcrossReboot
            if (!data.closeReceiverRegistered) {
                val filter = IntentFilter().apply {
                    addAction(Action.RELOAD)
                    addAction(Intent.ACTION_SHUTDOWN)
                    addAction(Action.CLOSE)
                    // addAction(Action.SWITCH_WAKE_LOCK)
                    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
                        addAction(PowerManager.ACTION_DEVICE_IDLE_MODE_CHANGED)
                    }
                    addAction(Action.RESET_UPSTREAM_CONNECTIONS)
                }
                if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
                    registerReceiver(
                        data.receiver,
                        filter,
                        "$packageName.SERVICE",
                        null,
                        Context.RECEIVER_EXPORTED
                    )
                } else {
                    registerReceiver(
                        data.receiver,
                        filter,
                        "$packageName.SERVICE",
                        null
                    )
                }
                data.closeReceiverRegistered = true
            }

            data.changeState(State.Connecting)
            runOnMainDispatcher {
                try {
                    data.notification = createNotification(ServiceNotification.genTitle(profile))

                    Executable.killAll()    // clean up old processes
                    preInit()
                    proxy.init()
                    DataStore.currentProfile = profile.id

                    proxy.processes = GuardedProcessPool {
                        Logs.w(it)
                        stopRunner(false, it.readableMessage)
                    }

                    startProcesses()
                    data.changeState(State.Connected)

                    lateInit()
                } catch (_: CancellationException) { // if the job was cancelled, it is canceller's responsibility to call stopRunner
                } catch (_: UnknownHostException) {
                    stopRunner(false, getString(R.string.invalid_server))
                } catch (e: PluginManager.PluginNotFoundException) {
                    Toast.makeText(this@Interface, e.readableMessage, Toast.LENGTH_SHORT).show()
                    Logs.w(e)
                    data.binder.missingPlugin(e.plugin)
                    stopRunner(false, null)
                } catch (exc: Throwable) {
                    if (exc.javaClass.name.endsWith("proxyerror")) {
                        // error from golang
                        Logs.w(exc.readableMessage)
                    } else {
                        Logs.w(exc)
                    }
                    stopRunner(
                        false, "${getString(R.string.service_failed)}: ${exc.readableMessage}"
                    )
                } finally {
                    data.connectingJob = null
                }
            }
            return Service.START_NOT_STICKY
        }
    }

}

================================================
FILE: app/src/main/java/io/nekohasekai/sagernet/bg/Executable.kt
================================================
package io.nekohasekai.sagernet.bg

import android.system.ErrnoException
import android.system.Os
import android.system.OsConstants
import io.nekohasekai.sagernet.ktx.Logs
import java.io.File
import java.io.IOException
import androidx.core.text.isDigitsOnly

object Executable {
    private val EXECUTABLES = setOf(
        "libtrojan.so", "libtrojan-go.so", "libnaive.so", "libtuic.so", "libhysteria.so"
    )

    fun killAll(alsoKillBg: Boolean = false) {
        // kill bg may fail
        for (process in File("/proc").listFiles { _, name -> name.isDigitsOnly() } ?: return) {
            val exe = File(
                try {
                File(process, "cmdline").inputStream().bufferedReader().use {
                    it.readText()
                }
            } catch (_: IOException) {
                continue
            }.split(Character.MIN_VALUE, limit = 2).first())
            if (EXECUTABLES.contains(exe.name) || (alsoKillBg && exe.name.endsWith(":bg"))) try {
                Os.kill(process.name.toInt(), OsConstants.SIGKILL)
                Logs.w("SIGKILL ${exe.name} (${process.name}) succeed")
            } catch (e: ErrnoException) {
                if (e.errno != OsConstants.ESRCH) {
                    Logs.w("SIGKILL ${exe.absolutePath} (${process.name}) failed")
                    Logs.w(e)
                }
            }
        }
    }
}


================================================
FILE: app/src/main/java/io/nekohasekai/sagernet/bg/GuardedProcessPool.kt
================================================
package io.nekohasekai.sagernet.bg

import android.os.Build
import android.os.SystemClock
import android.system.ErrnoException
import android.system.Os
import android.system.OsConstants
import androidx.annotation.MainThread
import io.nekohasekai.sagernet.SagerNet
import io.nekohasekai.sagernet.ktx.Logs
import io.nekohasekai.sagernet.utils.Commandline
import kotlinx.coroutines.*
import kotlinx.coroutines.channels.Channel
import libcore.Libcore
import java.io.File
import java.io.IOException
import java.io.InputStream
import kotlin.concurrent.thread

class GuardedProcessPool(private val onFatal: suspend (IOException) -> Unit) : CoroutineScope {
    companion object {
        private val pid by lazy {
            Class.forName("java.lang.ProcessManager\$ProcessImpl").getDeclaredField("pid")
                .apply { isAccessible = true }
        }
    }

    private inner class Guard(
        private val cmd: List<String>,
        private val env: Map<String, String> = mapOf()
    ) {
        private lateinit var process: Process

        private fun streamLogger(input: InputStream, logger: (String) -> Unit) = try {
            input.bufferedReader().forEachLine(logger)
        } catch (_: IOException) {
        }    // ignore

        fun start() {
            process = ProcessBuilder(cmd).directory(SagerNet.application.noBackupFilesDir).apply {
                environment().putAll(env)
            }.start()
        }

        @DelicateCoroutinesApi
        suspend fun looper(onRestartCallback: (suspend () -> Unit)?) {
            var running = true
            val cmdName = File(cmd.first()).nameWithoutExtension
            val exitChannel = Channel<Int>()
            try {
                while (true) {
                    thread(name = "stderr-$cmdName") {
                        streamLogger(process.errorStream) { Libcore.nekoLogPrintln("[$cmdName] $it") }
                    }
                    thread(name = "stdout-$cmdName") {
                        streamLogger(process.inputStream) { Libcore.nekoLogPrintln("[$cmdName] $it") }
                        // this thread also acts as a daemon thread for waitFor
                        runBlocking { exitChannel.send(process.waitFor()) }
                    }
                    val startTime = SystemClock.elapsedRealtime()
                    val exitCode = exitChannel.receive()
                    running = false
                    when {
                        SystemClock.elapsedRealtime() - startTime < 1000 -> throw IOException(
                            "$cmdName exits too fast (exit code: $exitCode)"
                        )

                        exitCode == 128 + OsConstants.SIGKILL -> Logs.w("$cmdName was killed")
                        else -> Logs.w(IOException("$cmdName unexpectedly exits with code $exitCode"))
                    }
                    Logs.i("restart process: ${Commandline.toString(cmd)} (last exit code: $exitCode)")
                    start()
                    running = true
                    onRestartCallback?.invoke()
                }
            } catch (e: IOException) {
                Logs.w("error occurred. stop guard: ${Commandline.toString(cmd)}")
                GlobalScope.launch(Dispatchers.Main) { onFatal(e) }
            } finally {
                if (running) withContext(NonCancellable) {  // clean-up cannot be cancelled
                    if (Build.VERSION.SDK_INT < 24) {
                        try {
                            Os.kill(pid.get(process) as Int, OsConstants.SIGTERM)
                        } catch (e: ErrnoException) {
                            if (e.errno != OsConstants.ESRCH) Logs.w(e)
                        } catch (e: ReflectiveOperationException) {
                            Logs.w(e)
                        }
                        if (withTimeoutOrNull(500) { exitChannel.receive() } != null) return@withContext
                    }
                    process.destroy()                       // kill the process
                    if (Build.VERSION.SDK_INT >= 26) {
                        if (withTimeoutOrNull(1000) { exitChannel.receive() } != null) return@withContext
                        process.destroyForcibly()           // Force to kill the process if it's still alive
                    }
                    exitChannel.receive()
                }                                           // otherwise process already exited, nothing to be done
            }
        }
    }

    override val coroutineContext = Dispatchers.Main.immediate + Job()
    var processCount = 0

    @MainThread
    fun start(
        cmd: List<String>,
        env: MutableMap<String, String> = mutableMapOf(),
        onRestartCallback: (suspend () -> Unit)? = null
    ) {
        Logs.i("start process: ${Commandline.toString(cmd)}")
        Guard(cmd, env).apply {
            start() // if start fails, IOException will be thrown directly
            launch { looper(onRestartCallback) }
        }
        processCount += 1
    }

    @MainThread
    fun close(scope: CoroutineScope) {
        cancel()
        coroutineContext[Job]!!.also { job -> scope.launch { job.cancelAndJoin() } }
    }
}


================================================
FILE: app/src/main/java/io/nekohasekai/sagernet/bg/ProxyService.kt
================================================
package io.nekohasekai.sagernet.bg

import android.annotation.SuppressLint
import android.app.Service
import android.content.Intent
import android.os.PowerManager
import io.nekohasekai.sagernet.SagerNet

class ProxyService : Service(), BaseService.Interface {
    override val data = BaseService.Data(this)
    override val tag: String get() = "SagerNetProxyService"
    override fun createNotification(profileName: String): ServiceNotification =
        ServiceNotification(this, profileName, "service-proxy", true)

    override var wakeLock: PowerManager.WakeLock? = null
    override var upstreamInterfaceName: String? = null

    @SuppressLint("WakelockTimeout")
    override fun acquireWakeLock() {
        wakeLock = SagerNet.power.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "sagernet:proxy")
            .apply { acquire() }
    }

    override fun onBind(intent: Intent) = super.onBind(intent)
    override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int =
        super<BaseService.Interface>.onStartCommand(intent, flags, startId)
}


================================================
FILE: app/src/main/java/io/nekohasekai/sagernet/bg/SagerConnection.kt
================================================
package io.nekohasekai.sagernet.bg

import android.content.ComponentName
import android.content.Context
import android.content.Intent
import android.content.ServiceConnection
import android.os.IBinder
import android.os.RemoteException
import io.nekohasekai.sagernet.Action
import io.nekohasekai.sagernet.Key
import io.nekohasekai.sagernet.aidl.ISagerNetService
import io.nekohasekai.sagernet.aidl.ISagerNetServiceCallback
import io.nekohasekai.sagernet.aidl.SpeedDisplayData
import io.nekohasekai.sagernet.aidl.TrafficData
import io.nekohasekai.sagernet.database.DataStore
import io.nekohasekai.sagernet.ktx.runOnMainDispatcher

class SagerConnection(
    private var connectionId: Int,
    private var listenForDeath: Boolean = false
) : ServiceConnection, IBinder.DeathRecipient {

    companion object {
        val serviceClass
            get() = when (DataStore.serviceMode) {
                Key.MODE_PROXY -> ProxyService::class
                Key.MODE_VPN -> VpnService::class
                else -> throw UnknownError()
            }.java

        const val CONNECTION_ID_SHORTCUT = 0
        const val CONNECTION_ID_TILE = 1
        const val CONNECTION_ID_MAIN_ACTIVITY_FOREGROUND = 2
        const val CONNECTION_ID_MAIN_ACTIVITY_BACKGROUND = 3
        const val CONNECTION_ID_RESTART_BG = 4

        var restartingApp = false
    }

    interface Callback {
        // smaller ISagerNetServiceCallback

        fun cbSpeedUpdate(stats: SpeedDisplayData) {}
        fun cbTrafficUpdate(data: TrafficData) {}
        fun cbSelectorUpdate(id: Long) {}

        fun stateChanged(state: BaseService.State, profileName: String?, msg: String?)

        fun missingPlugin(profileName: String, pluginName: String) {}

        fun onServiceConnected(service: ISagerNetService)

        /**
         * Different from Android framework, this method will be called even when you call `detachService`.
         */
        fun onServiceDisconnected() {}
        fun onBinderDied() {}
    }

    private var connectionActive = false
    private var callbackRegistered = false
    private var callback: Callback? = null
    private val serviceCallback = object : ISagerNetServiceCallback.Stub() {

        override fun stateChanged(state: Int, profileName: String?, msg: String?) {
            if (state < 0) return // skip private
            val s = BaseService.State.values()[state]
            DataStore.serviceState = s
            val callback = callback ?: return
            runOnMainDispatcher {
                callback.stateChanged(s, profileName, msg)
            }
        }

        override fun cbSpeedUpdate(stats: SpeedDisplayData) {
            val callback = callback ?: return
            runOnMainDispatcher {
                callback.cbSpeedUpdate(stats)
            }
        }

        override fun cbTrafficUpdate(stats: TrafficData) {
            val callback = callback ?: return
            runOnMainDispatcher {
                callback.cbTrafficUpdate(stats)
            }
        }

        override fun cbSelectorUpdate(id: Long) {
            val callback = callback ?: return
            runOnMainDispatcher {
                callback.cbSelectorUpdate(id)
            }
        }

        override fun missingPlugin(profileName: String, pluginName: String) {
            val callback = callback ?: return
            runOnMainDispatcher {
                callback.missingPlugin(profileName, pluginName)
            }
        }

    }

    private var binder: IBinder? = null

    var service: ISagerNetService? = null

    fun updateConnectionId(id: Int) {
        connectionId = id
        try {
            service?.registerCallback(serviceCallback, id)
        } catch (e: Exception) {
            e.printStackTrace()
        }
    }

    override fun onServiceConnected(name: ComponentName?, binder: IBinder) {
        this.binder = binder
        val service = ISagerNetService.Stub.asInterface(binder)!!
        this.service = service
        try {
            if (listenForDeath) binder.linkToDeath(this, 0)
            check(!callbackRegistered)
            service.registerCallback(serviceCallback, connectionId)
            callbackRegistered = true
        } catch (e: RemoteException) {
            e.printStackTrace()
        }
        callback?.onServiceConnected(service)
    }

    override fun onServiceDisconnected(name: ComponentName?) {
        unregisterCallback()
        callback?.onServiceDisconnected()
        service = null
        binder = null
    }

    override fun binderDied() {
        service = null
        callbackRegistered = false
        if (!restartingApp) {
            callback?.also { runOnMainDispatcher { it.onBinderDied() } }
        }
    }

    private fun unregisterCallback() {
        val service = service
        if (service != null && callbackRegistered) try {
            service.unregisterCallback(serviceCallback)
        } catch (_: RemoteException) {
        }
        callbackRegistered = false
    }

    fun connect(context: Context, callback: Callback?) {
        if (connectionActive) return
        connectionActive = true
        check(this.callback == null)
        this.callback = callback
        val intent = Intent(context, serviceClass).setAction(Action.SERVICE)
        context.bindService(intent, this, Context.BIND_AUTO_CREATE)
    }

    fun disconnect(context: Context) {
        unregisterCallback()
        if (connectionActive) try {
            context.unbindService(this)
        } catch (_: IllegalArgumentException) {
        }   // ignore
        connectionActive = false
        if (listenForDeath) try {
            binder?.unlinkToDeath(this, 0)
        } catch (_: NoSuchElementException) {
        }
        binder = null
        service = null
        callback = null
    }
}


================================================
FILE: app/src/main/java/io/nekohasekai/sagernet/bg/ServiceNotification.kt
================================================
package io.nekohasekai.sagernet.bg

import android.app.PendingIntent
import android.app.Service
import android.content.BroadcastReceiver
import android.content.Context
import android.content.Intent
import android.content.IntentFilter
import android.content.pm.ServiceInfo.FOREGROUND_SERVICE_TYPE_SYSTEM_EXEMPTED
import android.os.Build
import android.text.format.Formatter
import android.widget.Toast
import androidx.core.app.NotificationCompat
import androidx.core.app.NotificationManagerCompat
import io.nekohasekai.sagernet.Action
import io.nekohasekai.sagernet.R
import io.nekohasekai.sagernet.SagerNet
import io.nekohasekai.sagernet.aidl.SpeedDisplayData
import io.nekohasekai.sagernet.database.DataStore
import io.nekohasekai.sagernet.database.ProxyEntity
import io.nekohasekai.sagernet.database.SagerDatabase
import io.nekohasekai.sagernet.ktx.app
import io.nekohasekai.sagernet.ktx.getColorAttr
import io.nekohasekai.sagernet.ktx.runOnMainDispatcher
import io.nekohasekai.sagernet.ui.SwitchActivity
import io.nekohasekai.sagernet.utils.Theme
import kotlinx.coroutines.sync.Mutex
import kotlinx.coroutines.sync.withLock

/**
 * User can customize visibility of notification since Android 8.
 * The default visibility:
 *
 * Android 8.x: always visible due to system limitations
 * VPN:         always invisible because of VPN notification/icon
 * Other:       always visible
 *
 * See also: https://github.com/aosp-mirror/platform_frameworks_base/commit/070d142993403cc2c42eca808ff3fafcee220ac4
 */
class ServiceNotification(
    private val service: BaseService.Interface, title: String,
    channel: String, visible: Boolean = false,
) : BroadcastReceiver() {
    companion object {
        const val notificationId = 1
        val flags =
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) PendingIntent.FLAG_IMMUTABLE else 0

        fun genTitle(ent: ProxyEntity): String {
            val gn = if (DataStore.showGroupInNotification)
                SagerDatabase.groupDao.getById(ent.groupId)?.displayName() else null
            return if (gn == null) ent.displayName() else "[$gn] ${ent.displayName()}"
        }
    }

    var listenPostSpeed = true

    suspend fun postNotificationSpeedUpdate(stats: SpeedDisplayData) {
        useBuilder {
            if (showDirectSpeed) {
                val speedDetail = (service as Context).getString(
                    R.string.speed_detail, service.getString(
                        R.string.speed, Formatter.formatFileSize(service, stats.txRateProxy)
                    ), service.getString(
                        R.string.speed, Formatter.formatFileSize(service, stats.rxRateProxy)
                    ), service.getString(
                        R.string.speed,
                        Formatter.formatFileSize(service, stats.txRateDirect)
                    ), service.getString(
                        R.string.speed,
                        Formatter.formatFileSize(service, stats.rxRateDirect)
                    )
                )
                it.setStyle(NotificationCompat.BigTextStyle().bigText(speedDetail))
                it.setContentText(speedDetail)
            } else {
                val speedSimple = (service as Context).getString(
                    R.string.traffic, service.getString(
                        R.string.speed, Formatter.formatFileSize(service, stats.txRateProxy)
                    ), service.getString(
                        R.string.speed, Formatter.formatFileSize(service, stats.rxRateProxy)
                    )
                )
                it.setContentText(speedSimple)
            }
            it.setSubText(
                service.getString(
                    R.string.traffic,
                    Formatter.formatFileSize(service, stats.txTotal),
                    Formatter.formatFileSize(service, stats.rxTotal)
                )
            )
        }
        update()
    }

    suspend fun postNotificationTitle(newTitle: String) {
        useBuilder {
            it.setContentTitle(newTitle)
        }
        update()
    }

    suspend fun postNotificationWakeLockStatus(acquired: Boolean) {
        updateActions()
        useBuilder {
            it.priority =
                if (acquired) NotificationCompat.PRIORITY_HIGH else NotificationCompat.PRIORITY_LOW
        }
        update()
    }

    private val showDirectSpeed = DataStore.showDirectSpeed

    private val builder = NotificationCompat.Builder(service as Context, channel)
        .setWhen(0)
        .setTicker(service.getString(R.string.forward_success))
        .setContentTitle(title)
        .setOnlyAlertOnce(true)
        .setContentIntent(SagerNet.configureIntent(service))
        .setSmallIcon(R.drawable.ic_service_active)
        .setCategory(NotificationCompat.CATEGORY_SERVICE)
        .setPriority(if (visible) NotificationCompat.PRIORITY_LOW else NotificationCompat.PRIORITY_MIN)

    private val buildLock = Mutex()

    private suspend fun useBuilder(f: (NotificationCompat.Builder) -> Unit) {
        buildLock.withLock {
            f(builder)
        }
    }

    init {
        service as Context

        Theme.apply(app)
        Theme.apply(service)
        builder.color = service.getColorAttr(R.attr.colorPrimary)

        service.registerReceiver(this, IntentFilter().apply {
            addAction(Intent.ACTION_SCREEN_ON)
            addAction(Intent.ACTION_SCREEN_OFF)
        })

        runOnMainDispatcher {
            updateActions()
            show()
        }
    }

    private suspend fun updateActions() {
        service as Context
        useBuilder {
            it.clearActions()

            val closeAction = NotificationCompat.Action.Builder(
                0, service.getText(R.string.stop), PendingIntent.getBroadcast(
                    service, 0, Intent(Action.CLOSE).setPackage(service.packageName), flags
                )
            ).setShowsUserInterface(false).build()
            it.addAction(closeAction)

            val switchAction = NotificationCompat.Action.Builder(
                0, service.getString(R.string.action_switch), PendingIntent.getActivity(
                    service, 0, Intent(service, SwitchActivity::class.java), flags
                )
            ).setShowsUserInterface(false).build()
            it.addAction(switchAction)

            val resetUpstreamAction = NotificationCompat.Action.Builder(
                0, service.getString(R.string.reset_connections),
                PendingIntent.getBroadcast(
                    service, 0, Intent(Action.RESET_UPSTREAM_CONNECTIONS), flags
                )
            ).setShowsUserInterface(false).build()
            it.addAction(resetUpstreamAction)
        }
    }

    override fun onReceive(context: Context, intent: Intent) {
        if (service.data.state == BaseService.State.Connected) {
            listenPostSpeed = intent.action == Intent.ACTION_SCREEN_ON
        }
    }


    private suspend fun show() =
        useBuilder {
            try {
                if (Build.VERSION.SDK_INT >= 34) {
                    (service as Service).startForeground(
                        notificationId,
                        it.build(),
                        FOREGROUND_SERVICE_TYPE_SYSTEM_EXEMPTED
                    )
                } else {
                    (service as Service).startForeground(notificationId, it.build())
                }
            } catch (e: Exception) {
                Toast.makeText(
                    SagerNet.application,
                    "startForeground: $e",
                    Toast.LENGTH_LONG
                ).show()
            }
        }

    private suspend fun update() = useBuilder {
        NotificationManagerCompat.from(service as Service).notify(notificationId, it.build())
    }

    fun destroy() {
        listenPostSpeed = false
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
            (service as Service).stopForeground(Service.STOP_FOREGROUND_REMOVE)
        } else {
            (service as Service).stopForeground(true)
        }
        service.unregisterReceiver(this)
    }
}


================================================
FILE: app/src/main/java/io/nekohasekai/sagernet/bg/SubscriptionUpdater.kt
================================================
package io.nekohasekai.sagernet.bg

import android.content.Context
import androidx.core.app.NotificationCompat
import androidx.core.app.NotificationManagerCompat
import androidx.work.CoroutineWorker
import androidx.work.ExistingPeriodicWorkPolicy.UPDATE
import androidx.work.PeriodicWorkRequest
import androidx.work.WorkerParameters
import androidx.work.multiprocess.RemoteWorkManager
import io.nekohasekai.sagernet.R
import io.nekohasekai.sagernet.database.DataStore
import io.nekohasekai.sagernet.database.SagerDatabase
import io.nekohasekai.sagernet.group.GroupUpdater
import io.nekohasekai.sagernet.ktx.Logs
import io.nekohasekai.sagernet.ktx.app
import java.util.concurrent.TimeUnit

object SubscriptionUpdater {

    private const val WORK_NAME = "SubscriptionUpdater"

    suspend fun reconfigureUpdater() {
        RemoteWorkManager.getInstance(app).cancelUniqueWork(WORK_NAME)

        val subscriptions = SagerDatabase.groupDao.subscriptions()
            .filter { it.subscription!!.autoUpdate }
        if (subscriptions.isEmpty()) return

        // PeriodicWorkRequest.MIN_PERIODIC_INTERVAL_MILLIS
        var minDelay =
            subscriptions.minByOrNull { it.subscription!!.autoUpdateDelay }!!.subscription!!.autoUpdateDelay.toLong()
        val now = System.currentTimeMillis() / 1000L
        var minInitDelay =
            subscriptions.minOf { now - it.subscription!!.lastUpdated - (minDelay * 60) }
        if (minDelay < 15) minDelay = 15
        if (minInitDelay > 60) minInitDelay = 60

        // main process
        RemoteWorkManager.getInstance(app).enqueueUniquePeriodicWork(
            WORK_NAME,
            UPDATE,
            PeriodicWorkRequest.Builder(UpdateTask::class.java, minDelay, TimeUnit.MINUTES)
                .apply {
                    if (minInitDelay > 0) setInitialDelay(minInitDelay, TimeUnit.SECONDS)
                }
                .build()
        )
    }

    class UpdateTask(
        appContext: Context, params: WorkerParameters
    ) : CoroutineWorker(appContext, params) {

        val nm = NotificationManagerCompat.from(applicationContext)

        val notification = NotificationCompat.Builder(applicationContext, "service-subscription")
            .setWhen(0)
            .setTicker(applicationContext.getString(R.string.forward_success))
            .setContentTitle(applicationContext.getString(R.string.subscription_update))
            .setSmallIcon(R.drawable.ic_service_active)
            .setCategory(NotificationCompat.CATEGORY_SERVICE)

        override suspend fun doWork(): Result {
            var subscriptions =
                SagerDatabase.groupDao.subscriptions().filter { it.subscription!!.autoUpdate }
            if (!DataStore.serviceState.connected) {
                Logs.d("work: not connected")
                subscriptions = subscriptions.filter { !it.subscription!!.updateWhenConnectedOnly }
            }

            if (subscriptions.isNotEmpty()) for (profile in subscriptions) {
                val subscription = profile.subscription!!

                if (((System.currentTimeMillis() / 1000).toInt() - subscription.lastUpdated) < subscription.autoUpdateDelay * 60) {
                    Logs.d("work: not updating " + profile.displayName())
                    continue
                }
                Logs.d("work: updating " + profile.displayName())

                notification.setContentText(
                    applicationContext.getString(
                        R.string.subscription_update_message, profile.displayName()
                    )
                )
                nm.notify(2, notification.build())

                GroupUpdater.executeUpdate(profile, false)
            }

            nm.cancel(2)

            return Result.success()
        }
    }

}

================================================
FILE: app/src/main/java/io/nekohasekai/sagernet/bg/TileService.kt
================================================
package io.nekohasekai.sagernet.bg

import android.graphics.drawable.Icon
import android.service.quicksettings.Tile
import androidx.annotation.RequiresApi
import io.nekohasekai.sagernet.R
import io.nekohasekai.sagernet.SagerNet
import io.nekohasekai.sagernet.aidl.ISagerNetService
import io.nekohasekai.sagernet.database.SagerDatabase
import android.service.quicksettings.TileService as BaseTileService

@RequiresApi(24)
class TileService : BaseTileService(), SagerConnection.Callback {
    private val iconIdle by lazy { Icon.createWithResource(this, R.drawable.ic_service_idle) }
    private val iconBusy by lazy { Icon.createWithResource(this, R.drawable.ic_service_busy) }
    private val iconConnected by lazy {
        Icon.createWithResource(this, R.drawable.ic_service_active)
    }
    private var tapPending = false

    private val connection = SagerConnection(SagerConnection.CONNECTION_ID_TILE)
    override fun stateChanged(state: BaseService.State, profileName: String?, msg: String?) =
        updateTile(state, profileName)

    override fun onServiceConnected(service: ISagerNetService) {
        updateTile(BaseService.State.values()[service.state], service.profileName)
        if (tapPending) {
            tapPending = false
            onClick()
        }
    }

    override fun cbSelectorUpdate(id: Long) {
        val profile = SagerDatabase.proxyDao.getById(id) ?: return
        updateTile(BaseService.State.Connected, profile.displayName())
    }

    override fun onStartListening() {
        super.onStartListening()
        connection.connect(this, this)
    }

    override fun onStopListening() {
        connection.disconnect(this)
        super.onStopListening()
    }

    override fun onClick() {
        if (isLocked) unlockAndRun(this::toggle) else toggle()
    }

    private fun updateTile(serviceState: BaseService.State, profileName: String?) {
        qsTile?.apply {
            label = null
            when (serviceState) {
                BaseService.State.Idle -> error("serviceState")
                BaseService.State.Connecting -> {
                    icon = iconBusy
                    state = Tile.STATE_ACTIVE
                }

                BaseService.State.Connected -> {
                    icon = iconConnected
                    label = profileName
                    state = Tile.STATE_ACTIVE
                }

                BaseService.State.Stopping -> {
                    icon = iconBusy
                    state = Tile.STATE_UNAVAILABLE
                }

                BaseService.State.Stopped -> {
                    icon = iconIdle
                    state = Tile.STATE_INACTIVE
                }
            }
            label = label ?: getString(R.string.app_name)
            updateTile()
        }
    }

    private fun toggle() {
        val service = connection.service
        if (service == null) tapPending =
            true else BaseService.State.values()[service.state].let { state ->
            when {
                state.canStop -> SagerNet.stopService()
                state == BaseService.State.Stopped -> SagerNet.startService()
            }
        }
    }
}


================================================
FILE: app/src/main/java/io/nekohasekai/sagernet/bg/VpnService.kt
================================================
package io.nekohasekai.sagernet.bg

import android.Manifest
import android.annotation.SuppressLint
import android.app.Service
import android.content.Intent
import android.content.pm.PackageManager
import android.net.ProxyInfo
import android.os.Build
import android.os.ParcelFileDescriptor
import android.os.PowerManager
import io.nekohasekai.sagernet.*
import io.nekohasekai.sagernet.database.DataStore
import io.nekohasekai.sagernet.fmt.LOCALHOST
import io.nekohasekai.sagernet.fmt.hysteria.HysteriaBean
import io.nekohasekai.sagernet.ktx.*
import io.nekohasekai.sagernet.ui.VpnRequestActivity
import io.nekohasekai.sagernet.utils.Subnet
import android.net.VpnService as BaseVpnService

class VpnService : BaseVpnService(),
    BaseService.Interface {

    companion object {

        const val PRIVATE_VLAN4_CLIENT = "172.19.0.1"
        const val PRIVATE_VLAN4_ROUTER = "172.19.0.2"
        const val FAKEDNS_VLAN4_CLIENT = "198.18.0.0"
        const val PRIVATE_VLAN6_CLIENT = "fdfe:dcba:9876::1"
        const val PRIVATE_VLAN6_ROUTER = "fdfe:dcba:9876::2"

    }

    var conn: ParcelFileDescriptor? = null

    private var metered = false

    override var upstreamInterfaceName: String? = null

    override suspend fun startProcesses() {
        DataStore.vpnService = this
        super.startProcesses() // launch proxy instance
    }

    override var wakeLock: PowerManager.WakeLock? = null

    @SuppressLint("WakelockTimeout")
    override fun acquireWakeLock() {
        wakeLock = SagerNet.power.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "sagernet:vpn")
            .apply { acquire() }
    }

    @Suppress("EXPERIMENTAL_API_USAGE")
    override fun killProcesses() {
        conn?.close()
        conn = null
        super.killProcesses()
    }

    override fun onBind(intent: Intent) = when (intent.action) {
        SERVICE_INTERFACE -> super<BaseVpnService>.onBind(intent)
        else -> super<BaseService.Interface>.onBind(intent)
    }

    override val data = BaseService.Data(this)
    override val tag = "SagerNetVpnService"
    override fun createNotification(profileName: String) =
        ServiceNotification(this, profileName, "service-vpn")

    override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
        if (DataStore.serviceMode == Key.MODE_VPN) {
            if (prepare(this) != null) {
                startActivity(
                    Intent(
                        this, VpnRequestActivity::class.java
                    ).addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
                )
            } else return super<BaseService.Interface>.onStartCommand(intent, flags, startId)
        }
        stopRunner()
        return Service.START_NOT_STICKY
    }

    inner class NullConnectionException : NullPointerException(),
        BaseService.ExpectedException {
        override fun getLocalizedMessage() = getString(R.string.reboot_required)
    }

    fun startVpn(tunOptionsJson: String, tunPlatformOptionsJson: String): Int {
//        Logs.d(tunOptionsJson)
//        Logs.d(tunPlatformOptionsJson)
//        val tunOptions = JSONObject(tunOptionsJson)

        // address & route & MTU ...... use NB4A GUI config
        val builder = Builder().setConfigureIntent(SagerNet.configureIntent(this))
            .setSession(getString(R.string.app_name))
            .setMtu(DataStore.mtu)
        val ipv6Mode = DataStore.ipv6Mode

        // address
        builder.addAddress(PRIVATE_VLAN4_CLIENT, 30)
        if (ipv6Mode != IPv6Mode.DISABLE) {
            builder.addAddress(PRIVATE_VLAN6_CLIENT, 126)
        }
        builder.addDnsServer(PRIVATE_VLAN4_ROUTER)

        // route
        if (DataStore.bypassLan) {
            resources.getStringArray(R.array.bypass_private_route).forEach {
                val subnet = Subnet.fromString(it)!!
                builder.addRoute(subnet.address.hostAddress!!, subnet.prefixSize)
            }
            builder.addRoute(PRIVATE_VLAN4_ROUTER, 32)
            builder.addRoute(FAKEDNS_VLAN4_CLIENT, 15)
            // https://issuetracker.google.com/issues/149636790
            if (ipv6Mode != IPv6Mode.DISABLE) {
                builder.addRoute("2000::", 3)
            }
        } else {
            builder.addRoute("0.0.0.0", 0)
            if (ipv6Mode != IPv6Mode.DISABLE) {
                builder.addRoute("::", 0)
            }
        }

        updateUnderlyingNetwork(builder)
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) builder.setMetered(metered)

        // app route
        val packageName = packageName
        val proxyApps = DataStore.proxyApps
        var bypass = DataStore.bypass
        val workaroundSYSTEM = false /* DataStore.tunImplementation == TunImplementation.SYSTEM */
        val needBypassRootUid = workaroundSYSTEM || data.proxy!!.config.trafficMap.values.any {
            it[0].hysteriaBean?.protocol == HysteriaBean.PROTOCOL_FAKETCP
        }

        if (proxyApps || needBypassRootUid) {
            val individual = mutableSetOf<String>()
            val allApps by lazy {
                packageManager.getInstalledPackages(PackageManager.GET_PERMISSIONS).filter {
                    when (it.packageName) {
                        packageName -> false
                        "android" -> true
                        else -> it.requestedPermissions?.contains(Manifest.permission.INTERNET) == true
                    }
                }.map {
                    it.packageName
                }
            }
            if (proxyApps) {
                individual.addAll(DataStore.individual.split('\n').filter { it.isNotBlank() })
                if (bypass && needBypassRootUid) {
                    val individualNew = allApps.toMutableList()
                    individualNew.removeAll(individual)
                    individual.clear()
                    individual.addAll(individualNew)
                    bypass = false
                }
            } else {
                individual.addAll(allApps)
                bypass = false
            }

            val added = mutableListOf<String>()

            individual.apply {
                // Allow Matsuri itself using VPN.
                remove(packageName)
                if (!bypass) add(packageName)
            }.forEach {
                try {
                    if (bypass) {
                        builder.addDisallowedApplication(it)
                    } else {
                        builder.addAllowedApplication(it)
                    }
                    added.add(it)
                } catch (ex: PackageManager.NameNotFoundException) {
                    Logs.w(ex)
                }
            }

            if (bypass) {
                Logs.d("Add bypass: ${added.joinToString(", ")}")
            } else {
                Logs.d("Add allow: ${added.joinToString(", ")}")
            }
        }

        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q && DataStore.appendHttpProxy) {
            builder.setHttpProxy(ProxyInfo.buildDirectProxy(LOCALHOST, DataStore.mixedPort))
        }

        metered = DataStore.meteredNetwork
        if (Build.VERSION.SDK_INT >= 29) builder.setMetered(metered)
        conn = builder.establish() ?: throw NullConnectionException()

        return conn!!.fd
    }

    fun updateUnderlyingNetwork(builder: Builder? = null) {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP_MR1) {
            SagerNet.underlyingNetwork?.let {
                builder?.setUnderlyingNetworks(arrayOf(SagerNet.underlyingNetwork))
                    ?: setUnderlyingNetworks(arrayOf(SagerNet.underlyingNetwork))
            }
        }
    }

    override fun onRevoke() = stopRunner()

    override fun onDestroy() {
        DataStore.vpnService = null
        super.onDestroy()
        data.binder.close()
    }
}

================================================
FILE: app/src/main/java/io/nekohasekai/sagernet/bg/proto/BoxInstance.kt
================================================
package io.nekohasekai.sagernet.bg.proto

import android.os.SystemClock
import io.nekohasekai.sagernet.SagerNet
import io.nekohasekai.sagernet.bg.AbstractInstance
import io.nekohasekai.sagernet.bg.GuardedProcessPool
import io.nekohasekai.sagernet.database.DataStore
import io.nekohasekai.sagernet.database.ProxyEntity
import io.nekohasekai.sagernet.fmt.ConfigBuildResult
import io.nekohasekai.sagernet.fmt.buildConfig
import io.nekohasekai.sagernet.fmt.hysteria.HysteriaBean
import io.nekohasekai.sagernet.fmt.hysteria.buildHysteria1Config
import io.nekohasekai.sagernet.fmt.mieru.MieruBean
import io.nekohasekai.sagernet.fmt.mieru.buildMieruConfig
import io.nekohasekai.sagernet.fmt.naive.NaiveBean
import io.nekohasekai.sagernet.fmt.naive.buildNaiveConfig
import io.nekohasekai.sagernet.fmt.trojan_go.TrojanGoBean
import io.nekohasekai.sagernet.fmt.trojan_go.buildTrojanGoConfig
import io.nekohasekai.sagernet.ktx.*
import io.nekohasekai.sagernet.plugin.PluginManager
import kotlinx.coroutines.*
import libcore.BoxInstance
import libcore.Libcore
import moe.matsuri.nb4a.net.LocalResolverImpl
import java.io.File

abstract class BoxInstance(
    val profile: ProxyEntity
) : AbstractInstance {

    lateinit var config: ConfigBuildResult
    lateinit var box: BoxInstance

    val pluginPath = hashMapOf<String, PluginManager.InitResult>()
    val pluginConfigs = hashMapOf<Int, Pair<Int, String>>()
    val externalInstances = hashMapOf<Int, AbstractInstance>()
    open lateinit var processes: GuardedProcessPool
    private var cacheFiles = ArrayList<File>()
    fun isInitialized(): Boolean {
        return ::config.isInitialized && ::box.isInitialized
    }

    protected fun initPlugin(name: String): PluginManager.InitResult {
        return pluginPath.getOrPut(name) { PluginManager.init(name)!! }
    }

    protected open fun buildConfig() {
        config = buildConfig(profile)
    }

    protected open suspend fun loadConfig() {
        box = Libcore.newSingBoxInstance(config.config, LocalResolverImpl)
    }

    open suspend fun init() {
        buildConfig()
        for ((chain) in config.externalIndex) {
            chain.entries.forEachIndexed { index, (port, profile) ->
                when (val bean = profile.requireBean()) {
                    is TrojanGoBean -> {
                        initPlugin("trojan-go-plugin")
                        pluginConfigs[port] = profile.type to bean.buildTrojanGoConfig(port)
                    }

                    is MieruBean -> {
                        initPlugin("mieru-plugin")
                        pluginConfigs[port] = profile.type to bean.buildMieruConfig(port)
                    }

                    is NaiveBean -> {
                        initPlugin("naive-plugin")
                        pluginConfigs[port] = profile.type to bean.buildNaiveConfig(port)
                    }

                    is HysteriaBean -> {
                        initPlugin("hysteria-plugin")
                        pluginConfigs[port] = profile.type to bean.buildHysteria1Config(port) {
                            File(
                                app.cacheDir, "hysteria_" + SystemClock.elapsedRealtime() + ".ca"
                            ).apply {
                                parentFile?.mkdirs()
                                cacheFiles.add(this)
                            }
                        }
                    }
                }
            }
        }
        loadConfig()
    }

    override fun launch() {
        // TODO move, this is not box
        val cacheDir = File(SagerNet.application.cacheDir, "tmpcfg")
        cacheDir.mkdirs()

        for ((chain) in config.externalIndex) {
            chain.entries.forEachIndexed { index, (port, profile) ->
                val bean = profile.requireBean()
                val needChain = index != chain.size - 1
                val (profileType, config) = pluginConfigs[port] ?: (0 to "")

                when {
                    externalInstances.containsKey(port) -> {
                        externalInstances[port]!!.launch()
                    }

                    bean is TrojanGoBean -> {
                        val configFile = File(
                            cacheDir, "trojan_go_" + SystemClock.elapsedRealtime() + ".json"
                        )
                        configFile.parentFile?.mkdirs()
                        configFile.writeText(config)
                        cacheFiles.add(configFile)

                        val commands = mutableListOf(
                            initPlugin("trojan-go-plugin").path, "-config", configFile.absolutePath
                        )

                        processes.start(commands)
                    }

                    bean is MieruBean -> {
                        val configFile = File(
                            cacheDir, "mieru_" + SystemClock.elapsedRealtime() + ".json"
                        )

                        configFile.parentFile?.mkdirs()
                        configFile.writeText(config)
                        cacheFiles.add(configFile)

                        val envMap = mutableMapOf<String, String>()
                        envMap["MIERU_CONFIG_JSON_FILE"] = configFile.absolutePath
                        envMap["MIERU_PROTECT_PATH"] = "protect_path"

                        val commands = mutableListOf(
                            initPlugin("mieru-plugin").path, "run",
                        )

                        processes.start(commands, envMap)
                    }

                    bean is NaiveBean -> {
                        val configFile = File(
                            cacheDir, "naive_" + SystemClock.elapsedRealtime() + ".json"
                        )

                        configFile.parentFile?.mkdirs()
                        configFile.writeText(config)
                        cacheFiles.add(configFile)

                        val envMap = mutableMapOf<String, String>()

                        if (bean.certificates.isNotBlank()) {
                            val certFile = File(
                                cacheDir, "naive_" + SystemClock.elapsedRealtime() + ".crt"
                            )

                            certFile.parentFile?.mkdirs()
                            certFile.writeText(bean.certificates)
                            cacheFiles.add(certFile)

                            envMap["SSL_CERT_FILE"] = certFile.absolutePath
                        }

                        val commands = mutableListOf(
                            initPlugin("naive-plugin").path, configFile.absolutePath
                        )

                        processes.start(commands, envMap)
                    }

                    bean is HysteriaBean -> {
                        val configFile = File(
                            cacheDir, "hysteria_" + SystemClock.elapsedRealtime() + ".json"
                        )

                        configFile.parentFile?.mkdirs()
                        configFile.writeText(config)
                        cacheFiles.add(configFile)

                        val commands = mutableListOf(
                            initPlugin("hysteria-plugin").path,
                            "--no-check",
                            "--config",
                            configFile.absolutePath,
                            "--log-level",
                            if (DataStore.logLevel > 0) "trace" else "warn",
                            "client"
                        )

                        if (bean.protocol == HysteriaBean.PROTOCOL_FAKETCP) {
                            commands.addAll(0, listOf("su", "-c"))
                        }

                        processes.start(commands)
                    }
                }
            }
        }

        box.start()
    }

    @Suppress("EXPERIMENTAL_API_USAGE")
    override fun close() {
        for (instance in externalInstances.values) {
            runCatching {
                instance.close()
            }
        }

        cacheFiles.removeAll { it.delete(); true }

        if (::processes.isInitialized) processes.close(GlobalScope + Dispatchers.IO)

        if (::box.isInitialized) {
            box.close()
        }
    }

}

================================================
FILE: app/src/main/java/io/nekohasekai/sagernet/bg/proto/ProxyInstance.kt
================================================
package io.nekohasekai.sagernet.bg.proto

import io.nekohaseka
Download .txt
gitextract_rsn9ha2i/

├── .github/
│   ├── ISSUE_TEMPLATE/
│   │   ├── bug-report-en.md
│   │   ├── bug-report-zh_cn.md
│   │   ├── feature_request-en.md
│   │   └── feature_request-zh_cn.md
│   └── workflows/
│       ├── preview.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
│   │   │   └── 6.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
│           │   ├── proxy_packagename.txt
│           │   └── yacd.version.txt
│           ├── java/
│           │   ├── com/
│           │   │   └── github/
│           │   │       └── shadowsocks/
│           │   │           └── plugin/
│           │   │               ├── Utils.kt
│           │   │               └── fragment/
│           │   │                   └── AlertDialogFragment.kt
│           │   ├── 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
│           │   │           │   ├── GroupFragment.kt
│           │   │           │   ├── GroupSettingsActivity.kt
│           │   │           │   ├── LogcatFragment.kt
│           │   │           │   ├── MainActivity.kt
│           │   │           │   ├── NamedFragment.kt
│           │   │           │   ├── NetworkFragment.kt
│           │   │           │   ├── ProfileSelectActivity.kt
│           │   │           │   ├── QuickDisableShortcut.kt
│           │   │           │   ├── QuickEnableShortcut.kt
│           │   │           │   ├── RouteFragment.kt
│           │   │           │   ├── RouteSettingsActivity.kt
│           │   │           │   ├── ScannerActivity.kt
│           │   │           │   ├── SettingsFragment.kt
│           │   │           │   ├── SettingsPreferenceFragment.kt
│           │   │           │   ├── StunActivity.kt
│           │   │           │   ├── SwitchActivity.kt
│           │   │           │   ├── ThemedActivity.kt
│           │   │           │   ├── ToolbarFragment.kt
│           │   │           │   ├── ToolsFragment.kt
│           │   │           │   ├── VpnRequestActivity.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/
│           │   │           │   ├── Commandline.kt
│           │   │           │   ├── CrashHandler.kt
│           │   │           │   ├── DefaultNetworkListener.kt
│           │   │           │   ├── PackageCache.kt
│           │   │           │   ├── Subnet.kt
│           │   │           │   └── Theme.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
│           │               │   ├── ConnectionTestNotification.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/
│               │   ├── 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_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
│               ├── drawable-v26/
│               │   ├── ic_qu_camera_launcher.xml
│               │   └── ic_qu_shadowsocks_launcher.xml
│               ├── layout/
│               │   ├── item_keyboard_key.xml
│               │   ├── layout_about.xml
│               │   ├── layout_add_entity.xml
│               │   ├── layout_app_list.xml
│               │   ├── layout_app_placeholder.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_webview.xml
│               │   └── simple_menu_dropdown_item.xml
│               ├── menu/
│               │   ├── add_group_menu.xml
│               │   ├── add_profile_menu.xml
│               │   ├── add_route_menu.xml
│               │   ├── app_list_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
│               ├── raw/
│               │   ├── insecure.txt
│               │   ├── not_encrypted.txt
│               │   ├── shadowsocks_stream_cipher.txt
│               │   └── vmess_md5_auth.txt
│               ├── raw-zh-rCN/
│               │   ├── insecure.txt
│               │   ├── not_encrypted.txt
│               │   ├── shadowsocks_stream_cipher.txt
│               │   └── vmess_md5_auth.txt
│               ├── resources.properties
│               ├── values/
│               │   ├── arrays.xml
│               │   ├── attrs.xml
│               │   ├── colors.xml
│               │   ├── dimens.xml
│               │   ├── ic_launcher_background.xml
│               │   ├── strings.xml
│               │   └── themes.xml
│               ├── 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
│               └── 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
│                   └── 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/
│       │   ├── build.sh
│       │   ├── get_source.sh
│       │   ├── get_source_env.sh
│       │   └── init.sh
│       └── core.sh
├── buildSrc/
│   ├── build.gradle.kts
│   └── src/
│       └── main/
│           └── kotlin/
│               └── Helpers.kt
├── gradle/
│   └── wrapper/
│       ├── gradle-wrapper.jar
│       └── gradle-wrapper.properties
├── gradle.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_android.go
│   ├── dns_box.go
│   ├── ech/
│   │   └── ech.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/
│   │   ├── 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
│   └── stun.go
├── lint.xml
├── nb4a.properties
├── release.keystore
├── repositories.gradle.kts
├── run
└── settings.gradle.kts
Download .txt
SYMBOL INDEX (683 symbols across 60 files)

FILE: app/src/main/java/io/nekohasekai/sagernet/database/ParcelizeBridge.java
  class ParcelizeBridge (line 8) | public class ParcelizeBridge {
    method createRule (line 10) | public static RuleEntity createRule(Parcel parcel) {

FILE: app/src/main/java/io/nekohasekai/sagernet/database/SubscriptionBean.java
  class SubscriptionBean (line 13) | public class SubscriptionBean extends Serializable {
    method SubscriptionBean (line 42) | public SubscriptionBean() {
    method serializeToBuffer (line 45) | @Override
    method serializeForShare (line 64) | public void serializeForShare(ByteBufferOutput output) {
    method deserializeFromBuffer (line 77) | @Override
    method deserializeFromShare (line 93) | public void deserializeFromShare(ByteBufferInput input) {
    method initializeDefaultValues (line 104) | @Override
    method newInstance (line 126) | @NonNull
    method newArray (line 132) | @Override

FILE: app/src/main/java/io/nekohasekai/sagernet/fmt/AbstractBean.java
  class AbstractBean (line 15) | public abstract class AbstractBean extends Serializable {
    method displayName (line 31) | public String displayName() {
    method displayAddress (line 39) | public String displayAddress() {
    method network (line 43) | public String network() {
    method canICMPing (line 47) | public boolean canICMPing() {
    method canTCPing (line 51) | public boolean canTCPing() {
    method canMapping (line 55) | public boolean canMapping() {
    method initializeDefaultValues (line 59) | @Override
    method serializeToBuffer (line 81) | @Override
    method deserializeFromBuffer (line 93) | @Override
    method serialize (line 104) | public void serialize(ByteBufferOutput output) {
    method deserialize (line 109) | public void deserialize(ByteBufferInput input) {
    method clone (line 114) | @NotNull
    method equals (line 118) | @Override
    method hashCode (line 132) | @Override
    method toString (line 142) | @NotNull

FILE: app/src/main/java/io/nekohasekai/sagernet/fmt/KryoConverters.java
  class KryoConverters (line 34) | public class KryoConverters {
    method serialize (line 38) | @TypeConverter
    method deserialize (line 49) | public static <T extends Serializable> T deserialize(T bean, byte[] by...
    method socksDeserialize (line 62) | @TypeConverter
    method httpDeserialize (line 68) | @TypeConverter
    method shadowsocksDeserialize (line 74) | @TypeConverter
    method configDeserialize (line 80) | @TypeConverter
    method vmessDeserialize (line 86) | @TypeConverter
    method trojanDeserialize (line 92) | @TypeConverter
    method trojanGoDeserialize (line 98) | @TypeConverter
    method mieruDeserialize (line 104) | @TypeConverter
    method naiveDeserialize (line 110) | @TypeConverter
    method hysteriaDeserialize (line 116) | @TypeConverter
    method sshDeserialize (line 122) | @TypeConverter
    method wireguardDeserialize (line 128) | @TypeConverter
    method tuicDeserialize (line 134) | @TypeConverter
    method shadowTLSDeserialize (line 140) | @TypeConverter
    method anyTLSDeserialize (line 146) | @TypeConverter
    method chainDeserialize (line 153) | @TypeConverter
    method nekoDeserialize (line 159) | @TypeConverter
    method subscriptionDeserialize (line 165) | @TypeConverter

FILE: app/src/main/java/io/nekohasekai/sagernet/fmt/gson/GsonConverters.java
  class GsonConverters (line 13) | public class GsonConverters {
    method toJson (line 15) | @TypeConverter
    method toList (line 23) | @TypeConverter
    method toSet (line 29) | @TypeConverter

FILE: app/src/main/java/io/nekohasekai/sagernet/fmt/http/HttpBean.java
  class HttpBean (line 13) | public class HttpBean extends StandardV2RayBean {
    method initializeDefaultValues (line 18) | @Override
    method serialize (line 25) | @Override
    method deserialize (line 33) | @Override
    method clone (line 41) | @NotNull
    method newInstance (line 48) | @NonNull
    method newArray (line 54) | @Override

FILE: app/src/main/java/io/nekohasekai/sagernet/fmt/hysteria/HysteriaBean.java
  class HysteriaBean (line 15) | public class HysteriaBean extends AbstractBean {
    method canMapping (line 49) | @Override
    method initializeDefaultValues (line 54) | @Override
    method serialize (line 83) | @Override
    method deserialize (line 109) | @Override
    method displayAddress (line 153) | @Override
    method canTCPing (line 158) | @Override
    method clone (line 163) | @NotNull
    method newInstance (line 170) | @NonNull
    method newArray (line 176) | @Override

FILE: app/src/main/java/io/nekohasekai/sagernet/fmt/internal/ChainBean.java
  class ChainBean (line 16) | public class ChainBean extends InternalBean {
    method displayName (line 20) | @Override
    method initializeDefaultValues (line 29) | @Override
    method serialize (line 39) | @Override
    method deserialize (line 48) | @Override
    method clone (line 62) | @NotNull
    method newInstance (line 69) | @NonNull
    method newArray (line 75) | @Override

FILE: app/src/main/java/io/nekohasekai/sagernet/fmt/internal/InternalBean.java
  class InternalBean (line 5) | public abstract class InternalBean extends AbstractBean {
    method displayAddress (line 7) | @Override
    method canICMPing (line 12) | @Override
    method canTCPing (line 17) | @Override
    method canMapping (line 22) | @Override

FILE: app/src/main/java/io/nekohasekai/sagernet/fmt/mieru/MieruBean.java
  class MieruBean (line 31) | public class MieruBean extends AbstractBean {
    method initializeDefaultValues (line 38) | @Override
    method serialize (line 47) | @Override
    method deserialize (line 59) | @Override
    method clone (line 71) | @NotNull
    method newInstance (line 78) | @NonNull
    method newArray (line 84) | @Override

FILE: app/src/main/java/io/nekohasekai/sagernet/fmt/naive/NaiveBean.java
  class NaiveBean (line 13) | public class NaiveBean extends AbstractBean {
    method initializeDefaultValues (line 29) | @Override
    method serialize (line 43) | @Override
    method deserialize (line 58) | @Override
    method clone (line 78) | @NotNull
    method newInstance (line 85) | @NonNull
    method newArray (line 91) | @Override

FILE: app/src/main/java/io/nekohasekai/sagernet/fmt/shadowsocks/ShadowsocksBean.java
  class ShadowsocksBean (line 14) | public class ShadowsocksBean extends AbstractBean {
    method initializeDefaultValues (line 22) | @Override
    method serialize (line 33) | @Override
    method deserialize (line 43) | @Override
    method clone (line 53) | @NotNull
    method newInstance (line 60) | @NonNull
    method newArray (line 66) | @Override

FILE: app/src/main/java/io/nekohasekai/sagernet/fmt/socks/SOCKSBean.java
  class SOCKSBean (line 13) | public class SOCKSBean extends AbstractBean {
    method protocolVersion (line 19) | public int protocolVersion() {
    method protocolName (line 29) | public String protocolName() {
    method protocolVersionName (line 40) | public String protocolVersionName() {
    method network (line 58) | @Override
    method initializeDefaultValues (line 64) | @Override
    method serialize (line 74) | @Override
    method deserialize (line 84) | @Override
    method clone (line 98) | @NotNull
    method newInstance (line 105) | @NonNull
    method newArray (line 111) | @Override

FILE: app/src/main/java/io/nekohasekai/sagernet/fmt/ssh/SSHBean.java
  class SSHBean (line 13) | public class SSHBean extends AbstractBean {
    method initializeDefaultValues (line 26) | @Override
    method serialize (line 40) | @Override
    method deserialize (line 60) | @Override
    method clone (line 80) | @NotNull
    method newInstance (line 87) | @NonNull
    method newArray (line 93) | @Override

FILE: app/src/main/java/io/nekohasekai/sagernet/fmt/trojan/TrojanBean.java
  class TrojanBean (line 13) | public class TrojanBean extends StandardV2RayBean {
    method initializeDefaultValues (line 17) | @Override
    method serialize (line 24) | @Override
    method deserialize (line 31) | @Override
    method clone (line 50) | @NotNull
    method newInstance (line 57) | @NonNull
    method newArray (line 63) | @Override

FILE: app/src/main/java/io/nekohasekai/sagernet/fmt/trojan_go/TrojanGoBean.java
  class TrojanGoBean (line 14) | public class TrojanGoBean extends AbstractBean {
    method initializeDefaultValues (line 92) | @Override
    method serialize (line 106) | @Override
    method deserialize (line 126) | @Override
    method clone (line 149) | @NotNull
    method newInstance (line 156) | @NonNull
    method newArray (line 162) | @Override

FILE: app/src/main/java/io/nekohasekai/sagernet/fmt/tuic/TuicBean.java
  class TuicBean (line 13) | public class TuicBean extends AbstractBean {
    method initializeDefaultValues (line 36) | @Override
    method serialize (line 55) | @Override
    method deserialize (line 75) | @Override
    method canTCPing (line 101) | @Override
    method clone (line 106) | @NotNull
    method newInstance (line 113) | @NonNull
    method newArray (line 119) | @Override

FILE: app/src/main/java/io/nekohasekai/sagernet/fmt/v2ray/StandardV2RayBean.java
  class StandardV2RayBean (line 10) | public abstract class StandardV2RayBean extends AbstractBean {
    method initializeDefaultValues (line 69) | @Override
    method serialize (line 113) | @Override
    method deserialize (line 170) | @Override
    method isVLESS (line 261) | public boolean isVLESS() {

FILE: app/src/main/java/io/nekohasekai/sagernet/fmt/v2ray/VMessBean.java
  class VMessBean (line 10) | public class VMessBean extends StandardV2RayBean {
    method initializeDefaultValues (line 14) | @Override
    method clone (line 27) | @NotNull
    method newInstance (line 34) | @NonNull
    method newArray (line 40) | @Override

FILE: app/src/main/java/io/nekohasekai/sagernet/fmt/wireguard/WireGuardBean.java
  class WireGuardBean (line 13) | public class WireGuardBean extends AbstractBean {
    method initializeDefaultValues (line 22) | @Override
    method serialize (line 33) | @Override
    method deserialize (line 45) | @Override
    method canTCPing (line 57) | @Override
    method clone (line 62) | @NotNull
    method newInstance (line 69) | @NonNull
    method newArray (line 75) | @Override

FILE: app/src/main/java/moe/matsuri/nb4a/SingBoxOptions.java
  class SingBoxOptions (line 21) | public class SingBoxOptions {
    class SingBoxOption (line 34) | public static class SingBoxOption {
      method SingBoxOption (line 40) | public SingBoxOption() {
      method asMap (line 44) | public Map<String, Object> asMap() {
    class CustomSingBoxOption (line 50) | public static final class CustomSingBoxOption extends SingBoxOption {
      method CustomSingBoxOption (line 54) | public CustomSingBoxOption(String config) {
      method getBasicMap (line 59) | public Map<String, Object> getBasicMap() {
    class SingBoxOptionSerializer (line 69) | public static class SingBoxOptionSerializer implements JsonSerializer<...
      method serialize (line 70) | @Override
    class User (line 100) | public static class User {
    class MyOptions (line 105) | public static class MyOptions extends SingBoxOption {
    class ClashAPIOptions (line 124) | public static class ClashAPIOptions extends SingBoxOption {
    class SelectorOutboundOptions (line 142) | public static class SelectorOutboundOptions extends SingBoxOption {
    class URLTestOutboundOptions (line 151) | public static class URLTestOutboundOptions extends SingBoxOption {
    class Options (line 164) | public static class Options extends SingBoxOption {
    class LogOptions (line 184) | public static class LogOptions extends SingBoxOption {
    class DebugOptions (line 198) | public static class DebugOptions extends SingBoxOption {
    class DirectInboundOptions (line 219) | public static class DirectInboundOptions extends SingBoxOption {
    class DirectOutboundOptions (line 263) | public static class DirectOutboundOptions extends SingBoxOption {
    class DNSOptions (line 304) | public static class DNSOptions extends SingBoxOption {
    class DNSServerOptions (line 330) | public static class DNSServerOptions extends SingBoxOption {
    class DNSClientOptions (line 348) | public static class DNSClientOptions extends SingBoxOption {
    class DNSFakeIPOptions (line 360) | public static class DNSFakeIPOptions extends SingBoxOption {
    class ExperimentalOptions (line 370) | public static class ExperimentalOptions extends SingBoxOption {
    class CacheFile (line 382) | public static class CacheFile extends SingBoxOption {
    class HysteriaInboundOptions (line 394) | public static class HysteriaInboundOptions extends SingBoxOption {
    class HysteriaUser (line 454) | public static class HysteriaUser extends SingBoxOption {
    class HysteriaOutboundOptions (line 465) | public static class HysteriaOutboundOptions extends SingBoxOption {
    class Hysteria2InboundOptions (line 536) | public static class Hysteria2InboundOptions extends SingBoxOption {
    class Hysteria2Obfs (line 588) | public static class Hysteria2Obfs extends SingBoxOption {
    class Hysteria2User (line 596) | public static class Hysteria2User extends SingBoxOption {
    class Hysteria2OutboundOptions (line 604) | public static class Hysteria2OutboundOptions extends SingBoxOption {
    class Inbound (line 663) | public static class Inbound extends SingBoxOption {
    class InboundOptions (line 703) | public static class InboundOptions extends SingBoxOption {
    class ListenOptions (line 715) | public static class ListenOptions extends SingBoxOption {
    class NaiveInboundOptions (line 750) | public static class NaiveInboundOptions extends SingBoxOption {
    class NTPOptions (line 794) | public static class NTPOptions extends SingBoxOption {
    class Outbound (line 843) | public static class Outbound extends SingBoxOption {
    class DialerOptions (line 885) | public static class DialerOptions extends SingBoxOption {
    class ServerOptions (line 917) | public static class ServerOptions extends SingBoxOption {
    class MultiplexOptions (line 925) | public static class MultiplexOptions extends SingBoxOption {
    class OnDemandOptions (line 941) | public static class OnDemandOptions extends SingBoxOption {
    class OnDemandRule (line 949) | public static class OnDemandRule extends SingBoxOption {
    class RedirectInboundOptions (line 969) | public static class RedirectInboundOptions extends SingBoxOption {
    class TProxyInboundOptions (line 1007) | public static class TProxyInboundOptions extends SingBoxOption {
    class RouteOptions (line 1047) | public static class RouteOptions extends SingBoxOption {
    class Rule (line 1069) | public static class Rule extends SingBoxOption {
    class RuleSet (line 1079) | public static class RuleSet extends SingBoxOption {
    class DefaultRule (line 1093) | public static class DefaultRule extends SingBoxOption {
    class DNSRule (line 1163) | public static class DNSRule extends SingBoxOption {
    class DefaultDNSRule (line 1173) | public static class DefaultDNSRule extends SingBoxOption {
    class ShadowsocksInboundOptions (line 1252) | public static class ShadowsocksInboundOptions extends SingBoxOption {
    class ShadowsocksUser (line 1300) | public static class ShadowsocksUser extends SingBoxOption {
    class ShadowsocksDestination (line 1308) | public static class ShadowsocksDestination extends SingBoxOption {
    class ShadowsocksOutboundOptions (line 1323) | public static class ShadowsocksOutboundOptions extends SingBoxOption {
    class ShadowsocksROutboundOptions (line 1379) | public static class ShadowsocksROutboundOptions extends SingBoxOption {
    class ShadowTLSInboundOptions (line 1435) | public static class ShadowTLSInboundOptions extends SingBoxOption {
    class ShadowTLSUser (line 1485) | public static class ShadowTLSUser extends SingBoxOption {
    class ShadowTLSHandshakeOptions (line 1493) | public static class ShadowTLSHandshakeOptions extends SingBoxOption {
    class ShadowTLSOutboundOptions (line 1535) | public static class ShadowTLSOutboundOptions extends SingBoxOption {
    class SocksInboundOptions (line 1583) | public static class SocksInboundOptions extends SingBoxOption {
    class HTTPMixedInboundOptions (line 1623) | public static class HTTPMixedInboundOptions extends SingBoxOption {
    class SocksOutboundOptions (line 1667) | public static class SocksOutboundOptions extends SingBoxOption {
    class HTTPOutboundOptions (line 1719) | public static class HTTPOutboundOptions extends SingBoxOption {
    class SSHOutboundOptions (line 1771) | public static class SSHOutboundOptions extends SingBoxOption {
    class InboundTLSOptions (line 1831) | public static class InboundTLSOptions extends SingBoxOption {
    class OutboundTLSOptions (line 1867) | public static class OutboundTLSOptions extends SingBoxOption {
    class InboundRealityOptions (line 1899) | public static class InboundRealityOptions extends SingBoxOption {
    class InboundRealityHandshakeOptions (line 1914) | public static class InboundRealityHandshakeOptions extends SingBoxOpti...
    class InboundECHOptions (line 1956) | public static class InboundECHOptions extends SingBoxOption {
    class OutboundECHOptions (line 1967) | public static class OutboundECHOptions extends SingBoxOption {
    class OutboundUTLSOptions (line 1978) | public static class OutboundUTLSOptions extends SingBoxOption {
    class OutboundRealityOptions (line 1986) | public static class OutboundRealityOptions extends SingBoxOption {
    class InboundACMEOptions (line 1996) | public static class InboundACMEOptions extends SingBoxOption {
    class ACMEExternalAccountOptions (line 2021) | public static class ACMEExternalAccountOptions extends SingBoxOption {
    class TorOutboundOptions (line 2029) | public static class TorOutboundOptions extends SingBoxOption {
    class TrojanInboundOptions (line 2072) | public static class TrojanInboundOptions extends SingBoxOption {
    class TrojanUser (line 2120) | public static class TrojanUser extends SingBoxOption {
    class TrojanOutboundOptions (line 2128) | public static class TrojanOutboundOptions extends SingBoxOption {
    class TUICInboundOptions (line 2180) | public static class TUICInboundOptions extends SingBoxOption {
    class TUICUser (line 2230) | public static class TUICUser extends SingBoxOption {
    class TUICOutboundOptions (line 2240) | public static class TUICOutboundOptions extends SingBoxOption {
    class TunInboundOptions (line 2300) | public static class TunInboundOptions extends SingBoxOption {
    class TunPlatformOptions (line 2370) | public static class TunPlatformOptions extends SingBoxOption {
    class HTTPProxyOptions (line 2376) | public static class HTTPProxyOptions extends SingBoxOption {
    class UDPOverTCPOptions (line 2390) | public static class UDPOverTCPOptions extends SingBoxOption {
    class V2RayAPIOptions (line 2398) | public static class V2RayAPIOptions extends SingBoxOption {
    class V2RayStatsServiceOptions (line 2406) | public static class V2RayStatsServiceOptions extends SingBoxOption {
    class V2RayTransportOptions (line 2419) | public static class V2RayTransportOptions extends SingBoxOption {
    class V2RayHTTPOptions (line 2433) | public static class V2RayHTTPOptions extends SingBoxOption {
    class V2RayWebsocketOptions (line 2450) | public static class V2RayWebsocketOptions extends SingBoxOption {
    class V2RayGRPCOptions (line 2463) | public static class V2RayGRPCOptions extends SingBoxOption {
    class V2RayHTTPUpgradeOptions (line 2477) | public static class V2RayHTTPUpgradeOptions extends SingBoxOption {
    class VLESSInboundOptions (line 2487) | public static class VLESSInboundOptions extends SingBoxOption {
    class VLESSUser (line 2531) | public static class VLESSUser extends SingBoxOption {
    class VLESSOutboundOptions (line 2541) | public static class VLESSOutboundOptions extends SingBoxOption {
    class VMessInboundOptions (line 2597) | public static class VMessInboundOptions extends SingBoxOption {
    class VMessUser (line 2641) | public static class VMessUser extends SingBoxOption {
    class VMessOutboundOptions (line 2651) | public static class VMessOutboundOptions extends SingBoxOption {
    class WireGuardOutboundOptions (line 2713) | public static class WireGuardOutboundOptions extends SingBoxOption {
    class WireGuardPeer (line 2779) | public static class WireGuardPeer extends SingBoxOption {
    class Inbound_TunOptions (line 2800) | public static class Inbound_TunOptions extends Inbound {
    class Inbound_RedirectOptions (line 2870) | public static class Inbound_RedirectOptions extends Inbound {
    class Inbound_TProxyOptions (line 2907) | public static class Inbound_TProxyOptions extends Inbound {
    class Inbound_DirectOptions (line 2946) | public static class Inbound_DirectOptions extends Inbound {
    class Inbound_SocksOptions (line 2989) | public static class Inbound_SocksOptions extends Inbound {
    class Inbound_HTTPOptions (line 3028) | public static class Inbound_HTTPOptions extends Inbound {
    class Inbound_MixedOptions (line 3071) | public static class Inbound_MixedOptions extends Inbound {
    class Inbound_ShadowsocksOptions (line 3114) | public static class Inbound_ShadowsocksOptions extends Inbound {
    class Inbound_VMessOptions (line 3161) | public static class Inbound_VMessOptions extends Inbound {
    class Inbound_TrojanOptions (line 3204) | public static class Inbound_TrojanOptions extends Inbound {
    class Inbound_NaiveOptions (line 3251) | public static class Inbound_NaiveOptions extends Inbound {
    class Inbound_HysteriaOptions (line 3294) | public static class Inbound_HysteriaOptions extends Inbound {
    class Inbound_ShadowTLSOptions (line 3353) | public static class Inbound_ShadowTLSOptions extends Inbound {
    class Inbound_VLESSOptions (line 3402) | public static class Inbound_VLESSOptions extends Inbound {
    class Inbound_TUICOptions (line 3445) | public static class Inbound_TUICOptions extends Inbound {
    class Inbound_Hysteria2Options (line 3494) | public static class Inbound_Hysteria2Options extends Inbound {
    class Outbound_DirectOptions (line 3545) | public static class Outbound_DirectOptions extends Outbound {
    class Outbound_SocksOptions (line 3585) | public static class Outbound_SocksOptions extends Outbound {
    class Outbound_HTTPOptions (line 3636) | public static class Outbound_HTTPOptions extends Outbound {
    class Outbound_ShadowsocksOptions (line 3687) | public static class Outbound_ShadowsocksOptions extends Outbound {
    class Outbound_VMessOptions (line 3742) | public static class Outbound_VMessOptions extends Outbound {
    class Outbound_TrojanOptions (line 3803) | public static class Outbound_TrojanOptions extends Outbound {
    class Outbound_WireGuardOptions (line 3854) | public static class Outbound_WireGuardOptions extends Outbound {
    class Outbound_HysteriaOptions (line 3919) | public static class Outbound_HysteriaOptions extends Outbound {
    class Outbound_TorOptions (line 3989) | public static class Outbound_TorOptions extends Outbound {
    class Outbound_SSHOptions (line 4031) | public static class Outbound_SSHOptions extends Outbound {
    class Outbound_ShadowTLSOptions (line 4090) | public static class Outbound_ShadowTLSOptions extends Outbound {
    class Outbound_ShadowsocksROptions (line 4137) | public static class Outbound_ShadowsocksROptions extends Outbound {
    class Outbound_VLESSOptions (line 4192) | public static class Outbound_VLESSOptions extends Outbound {
    class Outbound_TUICOptions (line 4247) | public static class Outbound_TUICOptions extends Outbound {
    class Outbound_Hysteria2Options (line 4306) | public static class Outbound_Hysteria2Options extends Outbound {
    class Outbound_SelectorOptions (line 4363) | public static class Outbound_SelectorOptions extends Outbound {
    class Outbound_URLTestOptions (line 4372) | public static class Outbound_URLTestOptions extends Outbound {
    class Rule_DefaultOptions (line 4384) | public static class Rule_DefaultOptions extends Rule {
    class DNSRule_DefaultOptions (line 4461) | public static class DNSRule_DefaultOptions extends DNSRule {
    class V2RayTransportOptions_HTTPOptions (line 4539) | public static class V2RayTransportOptions_HTTPOptions extends V2RayTra...
    class V2RayTransportOptions_WebsocketOptions (line 4556) | public static class V2RayTransportOptions_WebsocketOptions extends V2R...
    class V2RayTransportOptions_GRPCOptions (line 4569) | public static class V2RayTransportOptions_GRPCOptions extends V2RayTra...
    class V2RayTransportOptions_HTTPUpgradeOptions (line 4582) | public static class V2RayTransportOptions_HTTPUpgradeOptions extends V...
    class Outbound_AnyTLSOptions (line 4593) | public static class Outbound_AnyTLSOptions extends Outbound {

FILE: app/src/main/java/moe/matsuri/nb4a/proxy/anytls/AnyTLSBean.java
  class AnyTLSBean (line 13) | public class AnyTLSBean extends AbstractBean {
    method newInstance (line 16) | @NonNull
    method newArray (line 22) | @Override
    method initializeDefaultValues (line 39) | @Override
    method serialize (line 51) | @Override
    method deserialize (line 64) | @Override
    method clone (line 77) | @NotNull

FILE: app/src/main/java/moe/matsuri/nb4a/proxy/config/ConfigBean.java
  class ConfigBean (line 15) | public class ConfigBean extends InternalBean {
    method initializeDefaultValues (line 20) | @Override
    method serialize (line 27) | @Override
    method deserialize (line 35) | @Override
    method displayName (line 43) | @Override
    method displayType (line 52) | public String displayType() {
    method clone (line 65) | @NotNull
    method newInstance (line 72) | @NonNull
    method newArray (line 78) | @Override

FILE: app/src/main/java/moe/matsuri/nb4a/proxy/neko/NekoBean.java
  class NekoBean (line 15) | public class NekoBean extends AbstractBean {
    method initializeDefaultValues (line 21) | @Override
    method serialize (line 28) | @Override
    method deserialize (line 37) | @Override
    method tryParseJSON (line 46) | @NotNull
    method displayType (line 58) | public String displayType() {
    method canMapping (line 62) | @Override
    method canICMPing (line 67) | @Override
    method canTCPing (line 72) | @Override
    method clone (line 77) | @NotNull
    method newInstance (line 84) | @NonNull
    method newArray (line 90) | @Override

FILE: app/src/main/java/moe/matsuri/nb4a/proxy/shadowtls/ShadowTLSBean.java
  class ShadowTLSBean (line 13) | public class ShadowTLSBean extends StandardV2RayBean {
    method initializeDefaultValues (line 18) | @Override
    method serialize (line 27) | @Override
    method deserialize (line 35) | @Override
    method clone (line 43) | @NotNull
    method newInstance (line 50) | @NonNull
    method newArray (line 56) | @Override

FILE: app/src/main/java/moe/matsuri/nb4a/utils/JavaUtil.java
  class JavaUtil (line 29) | public class JavaUtil {
    method unescapeString (line 44) | public static String unescapeString(CharSequence encodedString) {
    method handleWebviewDir (line 71) | public static void handleWebviewDir(Context context) {
    method tryLockOrRecreateFile (line 113) | @TargetApi(Build.VERSION_CODES.P)
    method createFile (line 132) | private static void createFile(File file, boolean deleted) {
    method checkIsHuaweiRom (line 142) | private static boolean checkIsHuaweiRom() {
    method getProcessName (line 146) | @SuppressLint("PrivateApi")
    method isNullOrBlank (line 166) | public static boolean isNullOrBlank(String str) {
    method isNotBlank (line 170) | public static boolean isNotBlank(String str) {
    method bytesToHex (line 176) | public static String bytesToHex(byte[] bytes) {
    method isEmpty (line 186) | public static boolean isEmpty(byte[] array) {

FILE: libcore/assets.go
  constant geoipDat (line 4) | geoipDat       = "geoip.db"
  constant geositeDat (line 5) | geositeDat     = "geosite.db"
  constant geoipVersion (line 6) | geoipVersion   = "geoip.version.txt"
  constant geositeVersion (line 7) | geositeVersion = "geosite.version.txt"
  constant yacdDstFolder (line 9) | yacdDstFolder = "yacd"
  constant yacdVersion (line 10) | yacdVersion   = "yacd.version.txt"

FILE: libcore/assets_android.go
  function extractAssets (line 16) | func extractAssets() {
  function extractAssetName (line 32) | func extractAssetName(name string, useOfficialAssets bool) error {
  function extractAsset (line 168) | func extractAsset(i asset.File, path string) error {

FILE: libcore/assets_other.go
  function extractAssets (line 5) | func extractAssets() {}

FILE: libcore/box.go
  function init (line 31) | func init() {
  function VersionBox (line 37) | func VersionBox() string {
  function ResetAllConnections (line 61) | func ResetAllConnections(system bool) {
  type BoxInstance (line 70) | type BoxInstance struct
    method Start (line 128) | func (b *BoxInstance) Start() (err error) {
    method Close (line 141) | func (b *BoxInstance) Close() (err error) {
    method Sleep (line 170) | func (b *BoxInstance) Sleep() {
    method Wake (line 177) | func (b *BoxInstance) Wake() {
    method SetAsMain (line 183) | func (b *BoxInstance) SetAsMain() {
    method SetV2rayStats (line 188) | func (b *BoxInstance) SetV2rayStats(outbounds string) {
    method QueryStats (line 202) | func (b *BoxInstance) QueryStats(tag, direct string) int64 {
    method SelectOutbound (line 209) | func (b *BoxInstance) SelectOutbound(tag string) bool {
  function NewSingBoxInstance (line 82) | func NewSingBoxInstance(config string, localTransport LocalDNSTransport)...
  function UrlTest (line 216) | func UrlTest(i *BoxInstance, link string, timeout int32) (latency int32,...
  function goServeProtect (line 239) | func goServeProtect(start bool) {

FILE: libcore/box_include.go
  function nekoboxAndroidInboundRegistry (line 45) | func nekoboxAndroidInboundRegistry() *inbound.Registry {
  function nekoboxAndroidOutboundRegistry (line 60) | func nekoboxAndroidOutboundRegistry() *outbound.Registry {
  function nekoboxAndroidEndpointRegistry (line 91) | func nekoboxAndroidEndpointRegistry() *endpoint.Registry {
  function nekoboxAndroidDNSTransportRegistry (line 99) | func nekoboxAndroidDNSTransportRegistry(localTransport LocalDNSTransport...
  function nekoboxAndroidServiceRegistry (line 124) | func nekoboxAndroidServiceRegistry() *service.Registry {

FILE: libcore/certs.go
  function updateRootCACerts (line 12) | func updateRootCACerts(pem []byte) {
  function initSystemRoots (line 24) | func initSystemRoots()

FILE: libcore/crypto.go
  function Sha1 (line 9) | func Sha1(data []byte) []byte {
  function Sha256Hex (line 14) | func Sha256Hex(data []byte) string {

FILE: libcore/device/debug.go
  function GoDebug (line 10) | func GoDebug(any interface{}) {
  function DeferPanicToError (line 16) | func DeferPanicToError(name string, onError func(error)) {

FILE: libcore/device/device.go
  function NumUDPWorkers (line 7) | func NumUDPWorkers() int {

FILE: libcore/dns_android.go
  function init (line 37) | func init() {

FILE: libcore/dns_box.go
  type LocalDNSTransport (line 26) | type LocalDNSTransport interface
  type platformLocalDNSTransport (line 35) | type platformLocalDNSTransport struct
    method Start (line 49) | func (p *platformLocalDNSTransport) Start(stage adapter.StartStage) er...
    method Close (line 53) | func (p *platformLocalDNSTransport) Close() error {
    method Exchange (line 57) | func (p *platformLocalDNSTransport) Exchange(ctx context.Context, mess...
  function newPlatformTransport (line 41) | func newPlatformTransport(iif LocalDNSTransport, tag string, options opt...
  type Func (line 123) | type Func interface
  type ExchangeContext (line 127) | type ExchangeContext struct
    method OnCancel (line 135) | func (c *ExchangeContext) OnCancel(callback Func) {
    method Success (line 142) | func (c *ExchangeContext) Success(result string) {
    method RawSuccess (line 150) | func (c *ExchangeContext) RawSuccess(result []byte) {
    method ErrorCode (line 158) | func (c *ExchangeContext) ErrorCode(code int32) {
    method ErrnoCode (line 163) | func (c *ExchangeContext) ErrnoCode(code int32) {

FILE: libcore/ech/ech.go
  type ECHClientConfig (line 17) | type ECHClientConfig struct
    method Client (line 33) | func (s *ECHClientConfig) Client(ctx context.Context, conn net.Conn) (...
    method fetchEchKeys (line 42) | func (s *ECHClientConfig) fetchEchKeys(ctx context.Context, conn net.C...
  function NewECHClientConfig (line 23) | func NewECHClientConfig(domain string, tlsConfig *tls.Config, localDnsTr...

FILE: libcore/fix.go
  type StringBox (line 6) | type StringBox struct
  function wrapString (line 10) | func wrapString(value string) *StringBox {

FILE: libcore/geoip.go
  type geoip (line 15) | type geoip struct
    method Open (line 19) | func (g *geoip) Open(path string) error {
    method Rules (line 25) | func (g *geoip) Rules(countryCode string) ([]option.HeadlessRule, erro...
  function init (line 61) | func init() {

FILE: libcore/geosite.go
  type geosite (line 13) | type geosite struct
    method Open (line 17) | func (g *geosite) Open(path string) error {
    method Rules (line 23) | func (g *geosite) Rules(code string) ([]option.HeadlessRule, error) {
  function init (line 46) | func init() {

FILE: libcore/http.go
  type HTTPClient (line 34) | type HTTPClient interface
  type HTTPRequest (line 46) | type HTTPRequest interface
  type HTTPResponse (line 57) | type HTTPResponse interface
  type httpClient (line 70) | type httpClient struct
    method ModernTLS (line 86) | func (c *httpClient) ModernTLS() {
    method RestrictedTLS (line 91) | func (c *httpClient) RestrictedTLS() {
    method PinnedTLS12 (line 100) | func (c *httpClient) PinnedTLS12() {
    method PinnedSHA256 (line 105) | func (c *httpClient) PinnedSHA256(sumHex string) {
    method TrySocks5 (line 117) | func (c *httpClient) TrySocks5(port int32) {
    method TryH3Direct (line 142) | func (c *httpClient) TryH3Direct() {
    method KeepAlive (line 146) | func (c *httpClient) KeepAlive() {
    method NewRequest (line 151) | func (c *httpClient) NewRequest() HTTPRequest {
    method Close (line 160) | func (c *httpClient) Close() {
  function NewHttpClient (line 78) | func NewHttpClient() HTTPClient {
  type httpRequest (line 164) | type httpRequest struct
    method AllowInsecure (line 169) | func (r *httpRequest) AllowInsecure() {
    method SetURL (line 173) | func (r *httpRequest) SetURL(link string) (err error) {
    method SetMethod (line 186) | func (r *httpRequest) SetMethod(method string) {
    method SetHeader (line 190) | func (r *httpRequest) SetHeader(key string, value string) {
    method SetUserAgent (line 194) | func (r *httpRequest) SetUserAgent(userAgent string) {
    method SetContent (line 198) | func (r *httpRequest) SetContent(content []byte) {
    method SetContentString (line 205) | func (r *httpRequest) SetContentString(content string) {
    method Execute (line 209) | func (r *httpRequest) Execute() (HTTPResponse, error) {
    method doH3Direct (line 232) | func (r *httpRequest) doH3Direct() (HTTPResponse, error) {
  type requestFunc (line 230) | type requestFunc
  type httpResponse (line 345) | type httpResponse struct
    method errorString (line 353) | func (h *httpResponse) errorString() string {
    method GetHeader (line 364) | func (h *httpResponse) GetHeader(key string) *StringBox {
    method GetContent (line 368) | func (h *httpResponse) GetContent() ([]byte, error) {
    method GetContentString (line 376) | func (h *httpResponse) GetContentString() (*StringBox, error) {
    method getContentString (line 384) | func (h *httpResponse) getContentString() (string, error) {
    method WriteTo (line 392) | func (h *httpResponse) WriteTo(path string) error {

FILE: libcore/interface_monitor.go
  type interfaceMonitorStub (line 11) | type interfaceMonitorStub struct
    method Start (line 13) | func (s *interfaceMonitorStub) Start() error {
    method Close (line 17) | func (s *interfaceMonitorStub) Close() error {
    method DefaultInterface (line 21) | func (s *interfaceMonitorStub) DefaultInterface() *control.Interface {
    method OverrideAndroidVPN (line 25) | func (s *interfaceMonitorStub) OverrideAndroidVPN() bool {
    method AndroidVPNEnabled (line 29) | func (s *interfaceMonitorStub) AndroidVPNEnabled() bool {
    method RegisterCallback (line 33) | func (s *interfaceMonitorStub) RegisterCallback(callback tun.DefaultIn...
    method UnregisterCallback (line 37) | func (s *interfaceMonitorStub) UnregisterCallback(element *list.Elemen...
    method RegisterMyInterface (line 40) | func (s *interfaceMonitorStub) RegisterMyInterface(interfaceName strin...
    method MyInterface (line 43) | func (s *interfaceMonitorStub) MyInterface() string {

FILE: libcore/io.go
  function Unxz (line 14) | func Unxz(archive string, path string) error {
  function Unzip (line 34) | func Unzip(archive string, path string) error {

FILE: libcore/nb4a.go
  function NekoLogPrintln (line 24) | func NekoLogPrintln(s string) {
  function NekoLogClear (line 28) | func NekoLogClear() {
  function ForceGc (line 32) | func ForceGc() {
  function InitCore (line 36) | func InitCore(process, cachePath, internalAssets, externalAssets string,
  function sendFdToProtect (line 88) | func sendFdToProtect(fd int, path string) error {

FILE: libcore/platform_box.go
  type boxPlatformInterfaceWrapper (line 28) | type boxPlatformInterfaceWrapper struct
    method ReadWIFIState (line 30) | func (w *boxPlatformInterfaceWrapper) ReadWIFIState() adapter.WIFIState {
    method Initialize (line 38) | func (w *boxPlatformInterfaceWrapper) Initialize(n adapter.NetworkMana...
    method UsePlatformAutoDetectInterfaceControl (line 42) | func (w *boxPlatformInterfaceWrapper) UsePlatformAutoDetectInterfaceCo...
    method AutoDetectInterfaceControl (line 46) | func (w *boxPlatformInterfaceWrapper) AutoDetectInterfaceControl(fd in...
    method OpenTun (line 56) | func (w *boxPlatformInterfaceWrapper) OpenTun(options *tun.Options, pl...
    method CloseTun (line 79) | func (w *boxPlatformInterfaceWrapper) CloseTun() error {
    method UsePlatformDefaultInterfaceMonitor (line 83) | func (w *boxPlatformInterfaceWrapper) UsePlatformDefaultInterfaceMonit...
    method CreateDefaultInterfaceMonitor (line 87) | func (w *boxPlatformInterfaceWrapper) CreateDefaultInterfaceMonitor(l ...
    method UsePlatformInterfaceGetter (line 91) | func (w *boxPlatformInterfaceWrapper) UsePlatformInterfaceGetter() bool {
    method Interfaces (line 95) | func (w *boxPlatformInterfaceWrapper) Interfaces() ([]adapter.NetworkI...
    method IncludeAllNetworks (line 99) | func (w *boxPlatformInterfaceWrapper) IncludeAllNetworks() bool {
    method SendNotification (line 103) | func (w *boxPlatformInterfaceWrapper) SendNotification(notification *p...
    method SystemCertificates (line 107) | func (s *boxPlatformInterfaceWrapper) SystemCertificates() []string {
    method UnderNetworkExtension (line 113) | func (w *boxPlatformInterfaceWrapper) UnderNetworkExtension() bool {
    method ClearDNSCache (line 117) | func (w *boxPlatformInterfaceWrapper) ClearDNSCache() {
    method FindProcessInfo (line 122) | func (w *boxPlatformInterfaceWrapper) FindProcessInfo(ctx context.Cont...
    method Write (line 153) | func (w *boxPlatformInterfaceWrapper) Write(p []byte) (n int, err erro...
  type boxPlatformLogWriterWrapper (line 163) | type boxPlatformLogWriterWrapper struct
    method DisableColors (line 168) | func (w *boxPlatformLogWriterWrapper) DisableColors() bool { return tr...
    method WriteMessage (line 170) | func (w *boxPlatformLogWriterWrapper) WriteMessage(level uint8, messag...

FILE: libcore/platform_java.go
  type NB4AInterface (line 9) | type NB4AInterface interface
  type BoxPlatformInterface (line 14) | type BoxPlatformInterface interface

FILE: libcore/procfs/procfs.go
  function init (line 24) | func init() {
  function ResolveSocketByProcSearch (line 33) | func ResolveSocketByProcSearch(network string, source, _ netip.AddrPort)...
  function nativeEndianIP (line 91) | func nativeEndianIP(ip net.IP) []byte {
  function init (line 103) | func init() {

FILE: libcore/stun.go
  type StunResult (line 10) | type StunResult struct
  function StunTest (line 15) | func StunTest(server string) *StunResult {

FILE: libcore/stun/attribute.go
  type attribute (line 23) | type attribute struct
    method xorAddr (line 68) | func (v *attribute) xorAddr(transID []byte) *Host {
    method rawAddr (line 94) | func (v *attribute) rawAddr() *Host {
  function newAttribute (line 29) | func newAttribute(types uint16, value []byte) *attribute {
  function newFingerprintAttribute (line 37) | func newFingerprintAttribute(packet *packet) *attribute {
  function newSoftwareAttribute (line 44) | func newSoftwareAttribute(name string) *attribute {
  function newChangeReqAttribute (line 48) | func newChangeReqAttribute(changeIP bool, changePort bool) *attribute {

FILE: libcore/stun/client.go
  type Client (line 25) | type Client struct
    method SetVerbose (line 53) | func (c *Client) SetVerbose(v bool) {
    method SetVVerbose (line 59) | func (c *Client) SetVVerbose(v bool) {
    method SetServerHost (line 64) | func (c *Client) SetServerHost(host string, port int) {
    method SetServerAddr (line 69) | func (c *Client) SetServerAddr(address string) {
    method SetSoftwareName (line 75) | func (c *Client) SetSoftwareName(name string) {
    method Discover (line 81) | func (c *Client) Discover() (NATType, *Host, error, bool) {
    method BehaviorTest (line 102) | func (c *Client) BehaviorTest() (*NATBehavior, error) {
    method Keepalive (line 125) | func (c *Client) Keepalive() (*Host, error) {
  function NewClient (line 34) | func NewClient() *Client {
  function NewClientWithConnection (line 43) | func NewClientWithConnection(conn net.PacketConn) *Client {

FILE: libcore/stun/const.go
  constant DefaultServerAddr (line 19) | DefaultServerAddr   = "stun.ekiga.net:3478"
  constant DefaultSoftwareName (line 20) | DefaultSoftwareName = "StunClient"
  constant magicCookie (line 24) | magicCookie = 0x2112A442
  constant fingerprint (line 25) | fingerprint = 0x5354554e
  type NATType (line 29) | type NATType
    method String (line 96) | func (nat NATType) String() string {
  type BehaviorType (line 32) | type BehaviorType
    method String (line 103) | func (natBhType BehaviorType) String() string {
  type NATBehavior (line 34) | type NATBehavior struct
    method NormalType (line 110) | func (natBehavior NATBehavior) NormalType() string {
  constant NATError (line 41) | NATError NATType = iota
  constant NATUnknown (line 42) | NATUnknown
  constant NATNone (line 43) | NATNone
  constant NATBlocked (line 44) | NATBlocked
  constant NATFull (line 45) | NATFull
  constant NATSymmetric (line 46) | NATSymmetric
  constant NATRestricted (line 47) | NATRestricted
  constant NATPortRestricted (line 48) | NATPortRestricted
  constant SymmetricUDPFirewall (line 49) | SymmetricUDPFirewall
  constant NATSymetric (line 52) | NATSymetric             = NATSymmetric
  constant NATSymetricUDPFirewall (line 53) | NATSymetricUDPFirewall  = SymmetricUDPFirewall
  constant NATSymmetricUDPFirewall (line 54) | NATSymmetricUDPFirewall = SymmetricUDPFirewall
  constant BehaviorTypeUnknown (line 58) | BehaviorTypeUnknown BehaviorType = iota
  constant BehaviorTypeEndpoint (line 59) | BehaviorTypeEndpoint
  constant BehaviorTypeAddr (line 60) | BehaviorTypeAddr
  constant BehaviorTypeAddrAndPort (line 61) | BehaviorTypeAddrAndPort
  function init (line 68) | func init() {
  constant errorTryAlternate (line 118) | errorTryAlternate                 = 300
  constant errorBadRequest (line 119) | errorBadRequest                   = 400
  constant errorUnauthorized (line 120) | errorUnauthorized                 = 401
  constant errorUnassigned402 (line 121) | errorUnassigned402                = 402
  constant errorForbidden (line 122) | errorForbidden                    = 403
  constant errorUnknownAttribute (line 123) | errorUnknownAttribute             = 420
  constant errorAllocationMismatch (line 124) | errorAllocationMismatch           = 437
  constant errorStaleNonce (line 125) | errorStaleNonce                   = 438
  constant errorUnassigned439 (line 126) | errorUnassigned439                = 439
  constant errorAddressFamilyNotSupported (line 127) | errorAddressFamilyNotSupported    = 440
  constant errorWrongCredentials (line 128) | errorWrongCredentials             = 441
  constant errorUnsupportedTransportProtocol (line 129) | errorUnsupportedTransportProtocol = 442
  constant errorPeerAddressFamilyMismatch (line 130) | errorPeerAddressFamilyMismatch    = 443
  constant errorConnectionAlreadyExists (line 131) | errorConnectionAlreadyExists      = 446
  constant errorConnectionTimeoutOrFailure (line 132) | errorConnectionTimeoutOrFailure   = 447
  constant errorAllocationQuotaReached (line 133) | errorAllocationQuotaReached       = 486
  constant errorRoleConflict (line 134) | errorRoleConflict                 = 487
  constant errorServerError (line 135) | errorServerError                  = 500
  constant errorInsufficientCapacity (line 136) | errorInsufficientCapacity         = 508
  constant attributeFamilyIPv4 (line 139) | attributeFamilyIPv4 = 0x01
  constant attributeFamilyIPV6 (line 140) | attributeFamilyIPV6 = 0x02
  constant attributeMappedAddress (line 144) | attributeMappedAddress          = 0x0001
  constant attributeResponseAddress (line 145) | attributeResponseAddress        = 0x0002
  constant attributeChangeRequest (line 146) | attributeChangeRequest          = 0x0003
  constant attributeSourceAddress (line 147) | attributeSourceAddress          = 0x0004
  constant attributeChangedAddress (line 148) | attributeChangedAddress         = 0x0005
  constant attributeUsername (line 149) | attributeUsername               = 0x0006
  constant attributePassword (line 150) | attributePassword               = 0x0007
  constant attributeMessageIntegrity (line 151) | attributeMessageIntegrity       = 0x0008
  constant attributeErrorCode (line 152) | attributeErrorCode              = 0x0009
  constant attributeUnknownAttributes (line 153) | attributeUnknownAttributes      = 0x000a
  constant attributeReflectedFrom (line 154) | attributeReflectedFrom          = 0x000b
  constant attributeChannelNumber (line 155) | attributeChannelNumber          = 0x000c
  constant attributeLifetime (line 156) | attributeLifetime               = 0x000d
  constant attributeBandwidth (line 157) | attributeBandwidth              = 0x0010
  constant attributeXorPeerAddress (line 158) | attributeXorPeerAddress         = 0x0012
  constant attributeData (line 159) | attributeData                   = 0x0013
  constant attributeRealm (line 160) | attributeRealm                  = 0x0014
  constant attributeNonce (line 161) | attributeNonce                  = 0x0015
  constant attributeXorRelayedAddress (line 162) | attributeXorRelayedAddress      = 0x0016
  constant attributeRequestedAddressFamily (line 163) | attributeRequestedAddressFamily = 0x0017
  constant attributeEvenPort (line 164) | attributeEvenPort               = 0x0018
  constant attributeRequestedTransport (line 165) | attributeRequestedTransport     = 0x0019
  constant attributeDontFragment (line 166) | attributeDontFragment           = 0x001a
  constant attributeXorMappedAddress (line 167) | attributeXorMappedAddress       = 0x0020
  constant attributeTimerVal (line 168) | attributeTimerVal               = 0x0021
  constant attributeReservationToken (line 169) | attributeReservationToken       = 0x0022
  constant attributePriority (line 170) | attributePriority               = 0x0024
  constant attributeUseCandidate (line 171) | attributeUseCandidate           = 0x0025
  constant attributePadding (line 172) | attributePadding                = 0x0026
  constant attributeResponsePort (line 173) | attributeResponsePort           = 0x0027
  constant attributeConnectionID (line 174) | attributeConnectionID           = 0x002a
  constant attributeXorMappedAddressExp (line 175) | attributeXorMappedAddressExp    = 0x8020
  constant attributeSoftware (line 176) | attributeSoftware               = 0x8022
  constant attributeAlternateServer (line 177) | attributeAlternateServer        = 0x8023
  constant attributeCacheTimeout (line 178) | attributeCacheTimeout           = 0x8027
  constant attributeFingerprint (line 179) | attributeFingerprint            = 0x8028
  constant attributeIceControlled (line 180) | attributeIceControlled          = 0x8029
  constant attributeIceControlling (line 181) | attributeIceControlling         = 0x802a
  constant attributeResponseOrigin (line 182) | attributeResponseOrigin         = 0x802b
  constant attributeOtherAddress (line 183) | attributeOtherAddress           = 0x802c
  constant attributeEcnCheckStun (line 184) | attributeEcnCheckStun           = 0x802d
  constant attributeCiscoFlowdata (line 185) | attributeCiscoFlowdata          = 0xc000
  constant typeBindingRequest (line 189) | typeBindingRequest                 = 0x0001
  constant typeBindingResponse (line 190) | typeBindingResponse                = 0x0101
  constant typeBindingErrorResponse (line 191) | typeBindingErrorResponse           = 0x0111
  constant typeSharedSecretRequest (line 192) | typeSharedSecretRequest            = 0x0002
  constant typeSharedSecretResponse (line 193) | typeSharedSecretResponse           = 0x0102
  constant typeSharedErrorResponse (line 194) | typeSharedErrorResponse            = 0x0112
  constant typeAllocate (line 195) | typeAllocate                       = 0x0003
  constant typeAllocateResponse (line 196) | typeAllocateResponse               = 0x0103
  constant typeAllocateErrorResponse (line 197) | typeAllocateErrorResponse          = 0x0113
  constant typeRefresh (line 198) | typeRefresh                        = 0x0004
  constant typeRefreshResponse (line 199) | typeRefreshResponse                = 0x0104
  constant typeRefreshErrorResponse (line 200) | typeRefreshErrorResponse           = 0x0114
  constant typeSend (line 201) | typeSend                           = 0x0006
  constant typeSendResponse (line 202) | typeSendResponse                   = 0x0106
  constant typeSendErrorResponse (line 203) | typeSendErrorResponse              = 0x0116
  constant typeData (line 204) | typeData                           = 0x0007
  constant typeDataResponse (line 205) | typeDataResponse                   = 0x0107
  constant typeDataErrorResponse (line 206) | typeDataErrorResponse              = 0x0117
  constant typeCreatePermisiion (line 207) | typeCreatePermisiion               = 0x0008
  constant typeCreatePermisiionResponse (line 208) | typeCreatePermisiionResponse       = 0x0108
  constant typeCreatePermisiionErrorResponse (line 209) | typeCreatePermisiionErrorResponse  = 0x0118
  constant typeChannelBinding (line 210) | typeChannelBinding                 = 0x0009
  constant typeChannelBindingResponse (line 211) | typeChannelBindingResponse         = 0x0109
  constant typeChannelBindingErrorResponse (line 212) | typeChannelBindingErrorResponse    = 0x0119
  constant typeConnect (line 213) | typeConnect                        = 0x000a
  constant typeConnectResponse (line 214) | typeConnectResponse                = 0x010a
  constant typeConnectErrorResponse (line 215) | typeConnectErrorResponse           = 0x011a
  constant typeConnectionBind (line 216) | typeConnectionBind                 = 0x000b
  constant typeConnectionBindResponse (line 217) | typeConnectionBindResponse         = 0x010b
  constant typeConnectionBindErrorResponse (line 218) | typeConnectionBindErrorResponse    = 0x011b
  constant typeConnectionAttempt (line 219) | typeConnectionAttempt              = 0x000c
  constant typeConnectionAttemptResponse (line 220) | typeConnectionAttemptResponse      = 0x010c
  constant typeConnectionAttemptErrorResponse (line 221) | typeConnectionAttemptErrorResponse = 0x011c

FILE: libcore/stun/discover.go
  method discover (line 66) | func (c *Client) discover(conn net.PacketConn, addr *net.UDPAddr) (_ NAT...
  method behaviorTest (line 168) | func (c *Client) behaviorTest(conn net.PacketConn, addr *net.UDPAddr) (*...

FILE: libcore/stun/host.go
  type Host (line 23) | type Host struct
    method Family (line 46) | func (h *Host) Family() uint16 {
    method IP (line 51) | func (h *Host) IP() string {
    method Port (line 56) | func (h *Host) Port() uint16 {
    method TransportAddr (line 61) | func (h *Host) TransportAddr() string {
    method String (line 66) | func (h *Host) String() string {
  function newHostFromStr (line 29) | func newHostFromStr(s string) *Host {

FILE: libcore/stun/log.go
  type Logger (line 23) | type Logger struct
    method SetDebug (line 36) | func (l *Logger) SetDebug(v bool) {
    method SetInfo (line 41) | func (l *Logger) SetInfo(v bool) {
    method Debug (line 46) | func (l *Logger) Debug(v ...interface{}) {
    method Debugf (line 53) | func (l *Logger) Debugf(format string, v ...interface{}) {
    method Debugln (line 60) | func (l *Logger) Debugln(v ...interface{}) {
    method Info (line 67) | func (l *Logger) Info(v ...interface{}) {
    method Infof (line 74) | func (l *Logger) Infof(format string, v ...interface{}) {
    method Infoln (line 81) | func (l *Logger) Infoln(v ...interface{}) {
  function NewLogger (line 30) | func NewLogger() *Logger {

FILE: libcore/stun/net.go
  constant numRetransmit (line 26) | numRetransmit  = 9
  constant defaultTimeout (line 27) | defaultTimeout = 100
  constant maxTimeout (line 28) | maxTimeout     = 1600
  constant maxPacketSize (line 29) | maxPacketSize  = 1024
  method sendBindingReq (line 32) | func (c *Client) sendBindingReq(conn net.PacketConn, addr net.Addr, chan...
  method send (line 59) | func (c *Client) send(pkt *packet, conn net.PacketConn, addr net.Addr) (...

FILE: libcore/stun/packet.go
  type packet (line 24) | type packet struct
    method addAttribute (line 72) | func (v *packet) addAttribute(a attribute) {
    method bytes (line 77) | func (v *packet) bytes() []byte {
    method getSourceAddr (line 93) | func (v *packet) getSourceAddr() *Host {
    method getMappedAddr (line 97) | func (v *packet) getMappedAddr() *Host {
    method getChangedAddr (line 101) | func (v *packet) getChangedAddr() *Host {
    method getOtherAddr (line 105) | func (v *packet) getOtherAddr() *Host {
    method getRawAddr (line 109) | func (v *packet) getRawAddr(attribute uint16) *Host {
    method getXorMappedAddr (line 118) | func (v *packet) getXorMappedAddr() *Host {
    method getXorAddr (line 126) | func (v *packet) getXorAddr(attribute uint16) *Host {
  function newPacket (line 31) | func newPacket() (*packet, error) {
  function newPacketFromBytes (line 44) | func newPacketFromBytes(packetBytes []byte) (*packet, error) {

FILE: libcore/stun/response.go
  type response (line 22) | type response struct
    method String (line 65) | func (r *response) String() string {
  function newResponse (line 31) | func newResponse(pkt *packet, conn net.PacketConn) *response {

FILE: libcore/stun/tests.go
  method sendWithLog (line 22) | func (c *Client) sendWithLog(conn net.PacketConn, addr *net.UDPAddr, cha...
  function addrCompare (line 39) | func addrCompare(host *Host, addr *net.UDPAddr, IPChange, portChange boo...
  method test (line 45) | func (c *Client) test(conn net.PacketConn, addr *net.UDPAddr) (*response...
  method testChangePort (line 49) | func (c *Client) testChangePort(conn net.PacketConn, addr *net.UDPAddr) ...
  method testChangeBoth (line 53) | func (c *Client) testChangeBoth(conn net.PacketConn, addr *net.UDPAddr) ...
  method test1 (line 57) | func (c *Client) test1(conn net.PacketConn, addr net.Addr) (*response, e...
  method test2 (line 61) | func (c *Client) test2(conn net.PacketConn, addr net.Addr) (*response, e...
  method test3 (line 65) | func (c *Client) test3(conn net.PacketConn, addr net.Addr) (*response, e...

FILE: libcore/stun/utils.go
  function padding (line 22) | func padding(bytes []byte) []byte {
  function align (line 29) | func align(n uint16) uint16 {
  function isLocalAddress (line 34) | func isLocalAddress(local, localRemote string) bool {
Condensed preview — 524 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (2,000K chars).
[
  {
    "path": ".github/ISSUE_TEMPLATE/bug-report-en.md",
    "chars": 459,
    "preview": "---\nname: 'Bug Report'\nabout: 'Please troubleshoot server-side issues and upgrade to the latest client before raising a "
  },
  {
    "path": ".github/ISSUE_TEMPLATE/bug-report-zh_cn.md",
    "chars": 193,
    "preview": "---\nname: '问题反馈'\nabout: '在提出问题前请先自行排除服务器端问题和升级到最新客户端。'\ntitle: 'BUG: '\nlabels: ''\nassignees: ''\n\n---\n\n## 描述问题\n\n预期行为:\n\n实际行"
  },
  {
    "path": ".github/ISSUE_TEMPLATE/feature_request-en.md",
    "chars": 188,
    "preview": "---\nname: 'Feature Request'\nabout: 'Make suggestions for new features of the software'\ntitle: ''\nlabels: ''\nassignees: '"
  },
  {
    "path": ".github/ISSUE_TEMPLATE/feature_request-zh_cn.md",
    "chars": 99,
    "preview": "---\nname: '功能请求'\nabout: '对软件的新功能提出建议。'\ntitle: ''\nlabels: ''\nassignees: ''\n\n---\n\n## 描述建议\n\n## 建议的必要性\n"
  },
  {
    "path": ".github/workflows/preview.yml",
    "chars": 2267,
    "preview": "name: Preview Build\non:\n  workflow_dispatch:\n    inputs:\njobs:\n  libcore:\n    name: Native Build (LibCore)\n    runs-on: "
  },
  {
    "path": ".github/workflows/release.yml",
    "chars": 4594,
    "preview": "name: Release Build\non:\n  workflow_dispatch:\n    inputs:\n      tag:\n        description: \"Release Tag\"\n        required:"
  },
  {
    "path": ".gitignore",
    "chars": 271,
    "preview": "*.iml\n.gradle\n.idea\n.vscode\n.DS_Store\nbuild/\n/captures\n.externalNativeBuild\n.cxx\nlocal.properties\n/app/libs/\n/app/src/ma"
  },
  {
    "path": "AUTHORS",
    "chars": 337,
    "preview": "SagerNet was originally created in late 2021, by\nnekohasekai <contact-sagernet@sekai.icu>.\n\nHere is an inevitably incomp"
  },
  {
    "path": "LICENSE",
    "chars": 674,
    "preview": "Copyright (C) 2021 by nekohasekai <contact-sagernet@sekai.icu>\n\nThis program is free software: you can redistribute it a"
  },
  {
    "path": "README.md",
    "chars": 2704,
    "preview": "# NekoBox for Android\n\n[![API](https://img.shields.io/badge/API-21%2B-brightgreen.svg?style=flat)](https://android-arsen"
  },
  {
    "path": "app/.gitignore",
    "chars": 7,
    "preview": "/build\n"
  },
  {
    "path": "app/build.gradle.kts",
    "chars": 3015,
    "preview": "@file:Suppress(\"UnstableApiUsage\")\n\nplugins {\n    id(\"com.android.application\")\n    id(\"kotlin-android\")\n    id(\"com.goo"
  },
  {
    "path": "app/executableSo/.gitignore",
    "chars": 5,
    "preview": "*.so\n"
  },
  {
    "path": "app/proguard-rules.pro",
    "chars": 1987,
    "preview": "-repackageclasses ''\n-allowaccessmodification\n\n-keep class io.nekohasekai.sagernet.** { *;}\n-keep class moe.matsuri.nb4a"
  },
  {
    "path": "app/schemas/io.nekohasekai.sagernet.database.SagerDatabase/1.json",
    "chars": 9707,
    "preview": "{\n  \"formatVersion\": 1,\n  \"database\": {\n    \"version\": 1,\n    \"identityHash\": \"f66fd943df1d9e86d281a2e32c9fdd47\",\n    \"e"
  },
  {
    "path": "app/schemas/io.nekohasekai.sagernet.database.SagerDatabase/2.json",
    "chars": 10500,
    "preview": "{\n  \"formatVersion\": 1,\n  \"database\": {\n    \"version\": 2,\n    \"identityHash\": \"9ec160533656482a17cbd563e9e3e416\",\n    \"e"
  },
  {
    "path": "app/schemas/io.nekohasekai.sagernet.database.SagerDatabase/3.json",
    "chars": 10681,
    "preview": "{\n  \"formatVersion\": 1,\n  \"database\": {\n    \"version\": 3,\n    \"identityHash\": \"cff00d0142d9e53d2ca24a6a55cd213c\",\n    \"e"
  },
  {
    "path": "app/schemas/io.nekohasekai.sagernet.database.SagerDatabase/4.json",
    "chars": 10681,
    "preview": "{\n  \"formatVersion\": 1,\n  \"database\": {\n    \"version\": 4,\n    \"identityHash\": \"cff00d0142d9e53d2ca24a6a55cd213c\",\n    \"e"
  },
  {
    "path": "app/schemas/io.nekohasekai.sagernet.database.SagerDatabase/5.json",
    "chars": 10865,
    "preview": "{\n  \"formatVersion\": 1,\n  \"database\": {\n    \"version\": 5,\n    \"identityHash\": \"1dbf667053726c13d139a4d83c41f895\",\n    \"e"
  },
  {
    "path": "app/schemas/io.nekohasekai.sagernet.database.SagerDatabase/6.json",
    "chars": 11090,
    "preview": "{\n  \"formatVersion\": 1,\n  \"database\": {\n    \"version\": 6,\n    \"identityHash\": \"3d3db9106a89d6f20ef3fde6e81dbaa9\",\n    \"e"
  },
  {
    "path": "app/schemas/io.nekohasekai.sagernet.database.preference.PublicDatabase/1.json",
    "chars": 1290,
    "preview": "{\n  \"formatVersion\": 1,\n  \"database\": {\n    \"version\": 1,\n    \"identityHash\": \"f1aab1fb633378621635c344dbc8ac7b\",\n    \"e"
  },
  {
    "path": "app/schemas/moe.matsuri.nb4a.TempDatabase/1.json",
    "chars": 1290,
    "preview": "{\n  \"formatVersion\": 1,\n  \"database\": {\n    \"version\": 1,\n    \"identityHash\": \"f1aab1fb633378621635c344dbc8ac7b\",\n    \"e"
  },
  {
    "path": "app/src/main/AndroidManifest.xml",
    "chars": 14927,
    "preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<manifest xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:to"
  },
  {
    "path": "app/src/main/aidl/io/nekohasekai/sagernet/aidl/ISagerNetService.aidl",
    "chars": 328,
    "preview": "package io.nekohasekai.sagernet.aidl;\n\nimport io.nekohasekai.sagernet.aidl.ISagerNetServiceCallback;\n\ninterface ISagerNe"
  },
  {
    "path": "app/src/main/aidl/io/nekohasekai/sagernet/aidl/ISagerNetServiceCallback.aidl",
    "chars": 443,
    "preview": "package io.nekohasekai.sagernet.aidl;\n\nimport io.nekohasekai.sagernet.aidl.SpeedDisplayData;\nimport io.nekohasekai.sager"
  },
  {
    "path": "app/src/main/aidl/io/nekohasekai/sagernet/aidl/SpeedDisplayData.aidl",
    "chars": 68,
    "preview": "package io.nekohasekai.sagernet.aidl;\n\nparcelable SpeedDisplayData;\n"
  },
  {
    "path": "app/src/main/aidl/io/nekohasekai/sagernet/aidl/TrafficData.aidl",
    "chars": 63,
    "preview": "package io.nekohasekai.sagernet.aidl;\n\nparcelable TrafficData;\n"
  },
  {
    "path": "app/src/main/assets/LICENSE",
    "chars": 673,
    "preview": "Copyright (C) 2021 by nekohasekai\n<contact-sagernet@sekai.icu>\n\nThis program is free software: you can\nredistribute it a"
  },
  {
    "path": "app/src/main/assets/proxy_packagename.txt",
    "chars": 9126,
    "preview": "amanita_design.samorost3.gp\nandroid\nau.com.shiftyjelly.pocketcasts\nbbc.mobile.news.ww\nbe.mygod.vpnhotspot\nch.protonmail."
  },
  {
    "path": "app/src/main/assets/yacd.version.txt",
    "chars": 1,
    "preview": "3"
  },
  {
    "path": "app/src/main/java/com/github/shadowsocks/plugin/Utils.kt",
    "chars": 163,
    "preview": "@file:JvmName(\"Utils\")\n\npackage com.github.shadowsocks.plugin\n\nimport android.os.Parcelable\nimport kotlinx.parcelize.Par"
  },
  {
    "path": "app/src/main/java/com/github/shadowsocks/plugin/fragment/AlertDialogFragment.kt",
    "chars": 2684,
    "preview": "package com.github.shadowsocks.plugin.fragment\n\nimport android.app.Activity\nimport android.content.DialogInterface\nimpor"
  },
  {
    "path": "app/src/main/java/io/nekohasekai/sagernet/BootReceiver.kt",
    "chars": 1624,
    "preview": "package io.nekohasekai.sagernet\n\nimport android.content.BroadcastReceiver\nimport android.content.ComponentName\nimport an"
  },
  {
    "path": "app/src/main/java/io/nekohasekai/sagernet/Constants.kt",
    "chars": 6719,
    "preview": "package io.nekohasekai.sagernet\n\nconst val CONNECTION_TEST_URL = \"http://cp.cloudflare.com/\"\n\nobject Key {\n\n    const va"
  },
  {
    "path": "app/src/main/java/io/nekohasekai/sagernet/QuickToggleShortcut.kt",
    "chars": 4225,
    "preview": "/*******************************************************************************\n *                                     "
  },
  {
    "path": "app/src/main/java/io/nekohasekai/sagernet/SagerNet.kt",
    "chars": 7752,
    "preview": "package io.nekohasekai.sagernet\n\nimport android.annotation.SuppressLint\nimport android.app.*\nimport android.content.Clip"
  },
  {
    "path": "app/src/main/java/io/nekohasekai/sagernet/aidl/SpeedDisplayData.kt",
    "chars": 452,
    "preview": "package io.nekohasekai.sagernet.aidl\n\nimport android.os.Parcelable\nimport kotlinx.parcelize.Parcelize\n\n@Parcelize\ndata c"
  },
  {
    "path": "app/src/main/java/io/nekohasekai/sagernet/aidl/TrafficData.kt",
    "chars": 222,
    "preview": "package io.nekohasekai.sagernet.aidl\n\nimport android.os.Parcelable\nimport kotlinx.parcelize.Parcelize\n\n@Parcelize\ndata c"
  },
  {
    "path": "app/src/main/java/io/nekohasekai/sagernet/bg/AbstractInstance.kt",
    "chars": 123,
    "preview": "package io.nekohasekai.sagernet.bg\n\nimport java.io.Closeable\n\ninterface AbstractInstance : Closeable {\n\n    fun launch()"
  },
  {
    "path": "app/src/main/java/io/nekohasekai/sagernet/bg/BaseService.kt",
    "chars": 14879,
    "preview": "package io.nekohasekai.sagernet.bg\n\nimport android.app.Service\nimport android.content.Context\nimport android.content.Int"
  },
  {
    "path": "app/src/main/java/io/nekohasekai/sagernet/bg/Executable.kt",
    "chars": 1382,
    "preview": "package io.nekohasekai.sagernet.bg\n\nimport android.system.ErrnoException\nimport android.system.Os\nimport android.system."
  },
  {
    "path": "app/src/main/java/io/nekohasekai/sagernet/bg/GuardedProcessPool.kt",
    "chars": 5206,
    "preview": "package io.nekohasekai.sagernet.bg\n\nimport android.os.Build\nimport android.os.SystemClock\nimport android.system.ErrnoExc"
  },
  {
    "path": "app/src/main/java/io/nekohasekai/sagernet/bg/ProxyService.kt",
    "chars": 1064,
    "preview": "package io.nekohasekai.sagernet.bg\n\nimport android.annotation.SuppressLint\nimport android.app.Service\nimport android.con"
  },
  {
    "path": "app/src/main/java/io/nekohasekai/sagernet/bg/SagerConnection.kt",
    "chars": 5801,
    "preview": "package io.nekohasekai.sagernet.bg\n\nimport android.content.ComponentName\nimport android.content.Context\nimport android.c"
  },
  {
    "path": "app/src/main/java/io/nekohasekai/sagernet/bg/ServiceNotification.kt",
    "chars": 8144,
    "preview": "package io.nekohasekai.sagernet.bg\n\nimport android.app.PendingIntent\nimport android.app.Service\nimport android.content.B"
  },
  {
    "path": "app/src/main/java/io/nekohasekai/sagernet/bg/SubscriptionUpdater.kt",
    "chars": 3789,
    "preview": "package io.nekohasekai.sagernet.bg\n\nimport android.content.Context\nimport androidx.core.app.NotificationCompat\nimport an"
  },
  {
    "path": "app/src/main/java/io/nekohasekai/sagernet/bg/TileService.kt",
    "chars": 3173,
    "preview": "package io.nekohasekai.sagernet.bg\n\nimport android.graphics.drawable.Icon\nimport android.service.quicksettings.Tile\nimpo"
  },
  {
    "path": "app/src/main/java/io/nekohasekai/sagernet/bg/VpnService.kt",
    "chars": 7839,
    "preview": "package io.nekohasekai.sagernet.bg\n\nimport android.Manifest\nimport android.annotation.SuppressLint\nimport android.app.Se"
  },
  {
    "path": "app/src/main/java/io/nekohasekai/sagernet/bg/proto/BoxInstance.kt",
    "chars": 8301,
    "preview": "package io.nekohasekai.sagernet.bg.proto\n\nimport android.os.SystemClock\nimport io.nekohasekai.sagernet.SagerNet\nimport i"
  },
  {
    "path": "app/src/main/java/io/nekohasekai/sagernet/bg/proto/ProxyInstance.kt",
    "chars": 1743,
    "preview": "package io.nekohasekai.sagernet.bg.proto\n\nimport io.nekohasekai.sagernet.BuildConfig\nimport io.nekohasekai.sagernet.bg.B"
  },
  {
    "path": "app/src/main/java/io/nekohasekai/sagernet/bg/proto/TestInstance.kt",
    "chars": 1767,
    "preview": "package io.nekohasekai.sagernet.bg.proto\n\nimport io.nekohasekai.sagernet.BuildConfig\nimport io.nekohasekai.sagernet.bg.G"
  },
  {
    "path": "app/src/main/java/io/nekohasekai/sagernet/bg/proto/TrafficLooper.kt",
    "chars": 6527,
    "preview": "package io.nekohasekai.sagernet.bg.proto\n\nimport io.nekohasekai.sagernet.aidl.SpeedDisplayData\nimport io.nekohasekai.sag"
  },
  {
    "path": "app/src/main/java/io/nekohasekai/sagernet/bg/proto/TrafficUpdater.kt",
    "chars": 1990,
    "preview": "package io.nekohasekai.sagernet.bg.proto\n\nclass TrafficUpdater(\n    private val box: libcore.BoxInstance,\n    val items:"
  },
  {
    "path": "app/src/main/java/io/nekohasekai/sagernet/bg/proto/UrlTest.kt",
    "chars": 358,
    "preview": "package io.nekohasekai.sagernet.bg.proto\n\nimport io.nekohasekai.sagernet.database.DataStore\nimport io.nekohasekai.sagern"
  },
  {
    "path": "app/src/main/java/io/nekohasekai/sagernet/database/DataStore.kt",
    "chars": 12871,
    "preview": "package io.nekohasekai.sagernet.database\n\nimport android.os.Binder\nimport androidx.preference.PreferenceDataStore\nimport"
  },
  {
    "path": "app/src/main/java/io/nekohasekai/sagernet/database/GroupManager.kt",
    "chars": 3468,
    "preview": "package io.nekohasekai.sagernet.database\n\nimport io.nekohasekai.sagernet.GroupType\nimport io.nekohasekai.sagernet.bg.Sub"
  },
  {
    "path": "app/src/main/java/io/nekohasekai/sagernet/database/ParcelizeBridge.java",
    "chars": 302,
    "preview": "package io.nekohasekai.sagernet.database;\n\nimport android.os.Parcel;\n\n/**\n * see: https://youtrack.jetbrains.com/issue/K"
  },
  {
    "path": "app/src/main/java/io/nekohasekai/sagernet/database/ProfileManager.kt",
    "chars": 7575,
    "preview": "package io.nekohasekai.sagernet.database\n\nimport android.database.sqlite.SQLiteCantOpenDatabaseException\nimport io.nekoh"
  },
  {
    "path": "app/src/main/java/io/nekohasekai/sagernet/database/ProxyEntity.kt",
    "chars": 18078,
    "preview": "package io.nekohasekai.sagernet.database\n\nimport android.content.Context\nimport android.content.Intent\nimport androidx.r"
  },
  {
    "path": "app/src/main/java/io/nekohasekai/sagernet/database/ProxyGroup.kt",
    "chars": 4083,
    "preview": "package io.nekohasekai.sagernet.database\n\nimport androidx.room.*\nimport com.esotericsoftware.kryo.io.ByteBufferInput\nimp"
  },
  {
    "path": "app/src/main/java/io/nekohasekai/sagernet/database/RuleEntity.kt",
    "chars": 3343,
    "preview": "package io.nekohasekai.sagernet.database\n\nimport android.os.Parcelable\nimport androidx.room.*\nimport io.nekohasekai.sage"
  },
  {
    "path": "app/src/main/java/io/nekohasekai/sagernet/database/SagerDatabase.kt",
    "chars": 1945,
    "preview": "package io.nekohasekai.sagernet.database\n\nimport androidx.room.AutoMigration\nimport androidx.room.Database\nimport androi"
  },
  {
    "path": "app/src/main/java/io/nekohasekai/sagernet/database/StringCollectionConverter.kt",
    "chars": 988,
    "preview": "package io.nekohasekai.sagernet.database\n\nimport androidx.room.TypeConverter\n\nclass StringCollectionConverter {\n    comp"
  },
  {
    "path": "app/src/main/java/io/nekohasekai/sagernet/database/SubscriptionBean.java",
    "chars": 4066,
    "preview": "package io.nekohasekai.sagernet.database;\n\nimport androidx.annotation.NonNull;\n\nimport com.esotericsoftware.kryo.io.Byte"
  },
  {
    "path": "app/src/main/java/io/nekohasekai/sagernet/database/preference/EditTextPreferenceModifiers.kt",
    "chars": 1429,
    "preview": "package io.nekohasekai.sagernet.database.preference\n\nimport android.graphics.Typeface\nimport android.text.InputFilter\nim"
  },
  {
    "path": "app/src/main/java/io/nekohasekai/sagernet/database/preference/KeyValuePair.kt",
    "chars": 4952,
    "preview": "package io.nekohasekai.sagernet.database.preference\n\nimport android.os.Parcel\nimport android.os.Parcelable\nimport androi"
  },
  {
    "path": "app/src/main/java/io/nekohasekai/sagernet/database/preference/OnPreferenceDataStoreChangeListener.kt",
    "chars": 229,
    "preview": "package io.nekohasekai.sagernet.database.preference\n\nimport androidx.preference.PreferenceDataStore\n\ninterface OnPrefere"
  },
  {
    "path": "app/src/main/java/io/nekohasekai/sagernet/database/preference/PublicDatabase.kt",
    "chars": 1133,
    "preview": "package io.nekohasekai.sagernet.database.preference\n\nimport androidx.room.Database\nimport androidx.room.Room\nimport andr"
  },
  {
    "path": "app/src/main/java/io/nekohasekai/sagernet/database/preference/RoomPreferenceDataStore.kt",
    "chars": 3363,
    "preview": "package io.nekohasekai.sagernet.database.preference\n\nimport androidx.preference.PreferenceDataStore\n\n@Suppress(\"MemberVi"
  },
  {
    "path": "app/src/main/java/io/nekohasekai/sagernet/fmt/AbstractBean.java",
    "chars": 3753,
    "preview": "package io.nekohasekai.sagernet.fmt;\n\nimport androidx.annotation.NonNull;\n\nimport com.esotericsoftware.kryo.io.ByteBuffe"
  },
  {
    "path": "app/src/main/java/io/nekohasekai/sagernet/fmt/ConfigBuilder.kt",
    "chars": 29192,
    "preview": "package io.nekohasekai.sagernet.fmt\n\nimport android.widget.Toast\nimport io.nekohasekai.sagernet.*\nimport io.nekohasekai."
  },
  {
    "path": "app/src/main/java/io/nekohasekai/sagernet/fmt/KryoConverters.java",
    "chars": 5785,
    "preview": "package io.nekohasekai.sagernet.fmt;\n\nimport androidx.room.TypeConverter;\n\nimport com.esotericsoftware.kryo.KryoExceptio"
  },
  {
    "path": "app/src/main/java/io/nekohasekai/sagernet/fmt/PluginEntry.kt",
    "chars": 1936,
    "preview": "package io.nekohasekai.sagernet.fmt\n\nimport io.nekohasekai.sagernet.R\nimport io.nekohasekai.sagernet.SagerNet\n\nenum clas"
  },
  {
    "path": "app/src/main/java/io/nekohasekai/sagernet/fmt/Serializable.kt",
    "chars": 850,
    "preview": "package io.nekohasekai.sagernet.fmt\n\nimport android.os.Parcel\nimport android.os.Parcelable\nimport com.esotericsoftware.k"
  },
  {
    "path": "app/src/main/java/io/nekohasekai/sagernet/fmt/TypeMap.kt",
    "chars": 999,
    "preview": "package io.nekohasekai.sagernet.fmt\n\nimport io.nekohasekai.sagernet.database.ProxyEntity\n\nobject TypeMap : HashMap<Strin"
  },
  {
    "path": "app/src/main/java/io/nekohasekai/sagernet/fmt/UniversalFmt.kt",
    "chars": 1287,
    "preview": "package io.nekohasekai.sagernet.fmt\n\nimport io.nekohasekai.sagernet.database.ProxyEntity\nimport io.nekohasekai.sagernet."
  },
  {
    "path": "app/src/main/java/io/nekohasekai/sagernet/fmt/gson/GsonConverters.java",
    "chars": 934,
    "preview": "package io.nekohasekai.sagernet.fmt.gson;\n\nimport androidx.room.TypeConverter;\n\nimport java.util.Collection;\nimport java"
  },
  {
    "path": "app/src/main/java/io/nekohasekai/sagernet/fmt/http/HttpBean.java",
    "chars": 1559,
    "preview": "package io.nekohasekai.sagernet.fmt.http;\n\nimport androidx.annotation.NonNull;\n\nimport com.esotericsoftware.kryo.io.Byte"
  },
  {
    "path": "app/src/main/java/io/nekohasekai/sagernet/fmt/http/HttpFmt.kt",
    "chars": 1282,
    "preview": "package io.nekohasekai.sagernet.fmt.http\n\nimport io.nekohasekai.sagernet.fmt.v2ray.isTLS\nimport io.nekohasekai.sagernet."
  },
  {
    "path": "app/src/main/java/io/nekohasekai/sagernet/fmt/hysteria/HysteriaBean.java",
    "chars": 5652,
    "preview": "package io.nekohasekai.sagernet.fmt.hysteria;\n\nimport androidx.annotation.NonNull;\n\nimport com.esotericsoftware.kryo.io."
  },
  {
    "path": "app/src/main/java/io/nekohasekai/sagernet/fmt/hysteria/HysteriaFmt.kt",
    "chars": 12517,
    "preview": "package io.nekohasekai.sagernet.fmt.hysteria\n\nimport io.nekohasekai.sagernet.database.DataStore\nimport io.nekohasekai.sa"
  },
  {
    "path": "app/src/main/java/io/nekohasekai/sagernet/fmt/internal/ChainBean.java",
    "chars": 1978,
    "preview": "package io.nekohasekai.sagernet.fmt.internal;\n\nimport androidx.annotation.NonNull;\n\nimport com.esotericsoftware.kryo.io."
  },
  {
    "path": "app/src/main/java/io/nekohasekai/sagernet/fmt/internal/InternalBean.java",
    "chars": 464,
    "preview": "package io.nekohasekai.sagernet.fmt.internal;\n\nimport io.nekohasekai.sagernet.fmt.AbstractBean;\n\npublic abstract class I"
  },
  {
    "path": "app/src/main/java/io/nekohasekai/sagernet/fmt/mieru/MieruBean.java",
    "chars": 3295,
    "preview": "/******************************************************************************\n * Copyright (C) 2022 by nekohasekai <co"
  },
  {
    "path": "app/src/main/java/io/nekohasekai/sagernet/fmt/mieru/MieruFmt.kt",
    "chars": 2507,
    "preview": "/******************************************************************************\n * Copyright (C) 2022 by nekohasekai <co"
  },
  {
    "path": "app/src/main/java/io/nekohasekai/sagernet/fmt/naive/NaiveBean.java",
    "chars": 2806,
    "preview": "package io.nekohasekai.sagernet.fmt.naive;\n\nimport androidx.annotation.NonNull;\n\nimport com.esotericsoftware.kryo.io.Byt"
  },
  {
    "path": "app/src/main/java/io/nekohasekai/sagernet/fmt/naive/NaiveFmt.kt",
    "chars": 3155,
    "preview": "package io.nekohasekai.sagernet.fmt.naive\n\nimport io.nekohasekai.sagernet.database.DataStore\nimport io.nekohasekai.sager"
  },
  {
    "path": "app/src/main/java/io/nekohasekai/sagernet/fmt/shadowsocks/ShadowsocksBean.java",
    "chars": 1990,
    "preview": "package io.nekohasekai.sagernet.fmt.shadowsocks;\n\nimport androidx.annotation.NonNull;\n\nimport com.esotericsoftware.kryo."
  },
  {
    "path": "app/src/main/java/io/nekohasekai/sagernet/fmt/shadowsocks/ShadowsocksFmt.kt",
    "chars": 3975,
    "preview": "package io.nekohasekai.sagernet.fmt.shadowsocks\n\nimport io.nekohasekai.sagernet.ktx.*\nimport moe.matsuri.nb4a.SingBoxOpt"
  },
  {
    "path": "app/src/main/java/io/nekohasekai/sagernet/fmt/socks/SOCKSBean.java",
    "chars": 2889,
    "preview": "package io.nekohasekai.sagernet.fmt.socks;\n\nimport androidx.annotation.NonNull;\n\nimport com.esotericsoftware.kryo.io.Byt"
  },
  {
    "path": "app/src/main/java/io/nekohasekai/sagernet/fmt/socks/SOCKSFmt.kt",
    "chars": 2391,
    "preview": "package io.nekohasekai.sagernet.fmt.socks\n\nimport io.nekohasekai.sagernet.ktx.decodeBase64UrlSafe\nimport io.nekohasekai."
  },
  {
    "path": "app/src/main/java/io/nekohasekai/sagernet/fmt/ssh/SSHBean.java",
    "chars": 2913,
    "preview": "package io.nekohasekai.sagernet.fmt.ssh;\n\nimport androidx.annotation.NonNull;\n\nimport com.esotericsoftware.kryo.io.ByteB"
  },
  {
    "path": "app/src/main/java/io/nekohasekai/sagernet/fmt/ssh/SSHFmt.kt",
    "chars": 805,
    "preview": "package io.nekohasekai.sagernet.fmt.ssh\n\nimport moe.matsuri.nb4a.SingBoxOptions\nimport moe.matsuri.nb4a.utils.listByLine"
  },
  {
    "path": "app/src/main/java/io/nekohasekai/sagernet/fmt/trojan/TrojanBean.java",
    "chars": 1968,
    "preview": "package io.nekohasekai.sagernet.fmt.trojan;\n\nimport androidx.annotation.NonNull;\n\nimport com.esotericsoftware.kryo.io.By"
  },
  {
    "path": "app/src/main/java/io/nekohasekai/sagernet/fmt/trojan/TrojanFmt.kt",
    "chars": 593,
    "preview": "package io.nekohasekai.sagernet.fmt.trojan\n\nimport io.nekohasekai.sagernet.fmt.v2ray.parseDuckSoft\nimport okhttp3.HttpUr"
  },
  {
    "path": "app/src/main/java/io/nekohasekai/sagernet/fmt/trojan_go/TrojanGoBean.java",
    "chars": 4226,
    "preview": "package io.nekohasekai.sagernet.fmt.trojan_go;\n\nimport androidx.annotation.NonNull;\n\nimport com.esotericsoftware.kryo.io"
  },
  {
    "path": "app/src/main/java/io/nekohasekai/sagernet/fmt/trojan_go/TrojanGoFmt.kt",
    "chars": 5025,
    "preview": "package io.nekohasekai.sagernet.fmt.trojan_go\n\nimport io.nekohasekai.sagernet.IPv6Mode\nimport io.nekohasekai.sagernet.da"
  },
  {
    "path": "app/src/main/java/io/nekohasekai/sagernet/fmt/tuic/TuicBean.java",
    "chars": 3692,
    "preview": "package io.nekohasekai.sagernet.fmt.tuic;\n\nimport androidx.annotation.NonNull;\n\nimport com.esotericsoftware.kryo.io.Byte"
  },
  {
    "path": "app/src/main/java/io/nekohasekai/sagernet/fmt/tuic/TuicFmt.kt",
    "chars": 3358,
    "preview": "package io.nekohasekai.sagernet.fmt.tuic\n\nimport io.nekohasekai.sagernet.database.DataStore\nimport io.nekohasekai.sagern"
  },
  {
    "path": "app/src/main/java/io/nekohasekai/sagernet/fmt/v2ray/StandardV2RayBean.java",
    "chars": 7869,
    "preview": "package io.nekohasekai.sagernet.fmt.v2ray;\n\nimport com.esotericsoftware.kryo.io.ByteBufferInput;\nimport com.esotericsoft"
  },
  {
    "path": "app/src/main/java/io/nekohasekai/sagernet/fmt/v2ray/V2RayFmt.kt",
    "chars": 20876,
    "preview": "package io.nekohasekai.sagernet.fmt.v2ray\n\nimport android.text.TextUtils\nimport com.google.gson.Gson\nimport io.nekohasek"
  },
  {
    "path": "app/src/main/java/io/nekohasekai/sagernet/fmt/v2ray/VMessBean.java",
    "chars": 1178,
    "preview": "package io.nekohasekai.sagernet.fmt.v2ray;\n\nimport androidx.annotation.NonNull;\n\nimport org.jetbrains.annotations.NotNul"
  },
  {
    "path": "app/src/main/java/io/nekohasekai/sagernet/fmt/wireguard/WireGuardBean.java",
    "chars": 2337,
    "preview": "package io.nekohasekai.sagernet.fmt.wireguard;\n\nimport androidx.annotation.NonNull;\n\nimport com.esotericsoftware.kryo.io"
  },
  {
    "path": "app/src/main/java/io/nekohasekai/sagernet/fmt/wireguard/WireGuardFmt.kt",
    "chars": 1344,
    "preview": "package io.nekohasekai.sagernet.fmt.wireguard\n\nimport moe.matsuri.nb4a.SingBoxOptions\nimport moe.matsuri.nb4a.utils.Util"
  },
  {
    "path": "app/src/main/java/io/nekohasekai/sagernet/group/GroupInterfaceAdapter.kt",
    "chars": 3754,
    "preview": "package io.nekohasekai.sagernet.group\n\nimport com.google.android.material.dialog.MaterialAlertDialogBuilder\nimport io.ne"
  },
  {
    "path": "app/src/main/java/io/nekohasekai/sagernet/group/GroupUpdater.kt",
    "chars": 6157,
    "preview": "package io.nekohasekai.sagernet.group\n\nimport io.nekohasekai.sagernet.*\nimport io.nekohasekai.sagernet.database.DataStor"
  },
  {
    "path": "app/src/main/java/io/nekohasekai/sagernet/group/RawUpdater.kt",
    "chars": 37024,
    "preview": "package io.nekohasekai.sagernet.group\n\nimport android.annotation.SuppressLint\nimport io.nekohasekai.sagernet.R\nimport io"
  },
  {
    "path": "app/src/main/java/io/nekohasekai/sagernet/ktx/Asyncs.kt",
    "chars": 1384,
    "preview": "@file:Suppress(\"EXPERIMENTAL_API_USAGE\")\n\npackage io.nekohasekai.sagernet.ktx\n\nimport androidx.fragment.app.Fragment\nimp"
  },
  {
    "path": "app/src/main/java/io/nekohasekai/sagernet/ktx/Browsers.kt",
    "chars": 1016,
    "preview": "  package io.nekohasekai.sagernet.ktx\n\nimport android.content.Context\nimport android.net.Uri\nimport androidx.browser.cus"
  },
  {
    "path": "app/src/main/java/io/nekohasekai/sagernet/ktx/Dialogs.kt",
    "chars": 771,
    "preview": "package io.nekohasekai.sagernet.ktx\n\nimport android.app.Activity\nimport android.content.Context\nimport androidx.appcompa"
  },
  {
    "path": "app/src/main/java/io/nekohasekai/sagernet/ktx/Dimens.kt",
    "chars": 307,
    "preview": "package io.nekohasekai.sagernet.ktx\n\nimport android.content.res.Resources\nimport kotlin.math.ceil\n\nprivate val density ="
  },
  {
    "path": "app/src/main/java/io/nekohasekai/sagernet/ktx/Formats.kt",
    "chars": 7555,
    "preview": "package io.nekohasekai.sagernet.ktx\n\nimport com.google.gson.JsonParser\nimport io.nekohasekai.sagernet.fmt.AbstractBean\ni"
  },
  {
    "path": "app/src/main/java/io/nekohasekai/sagernet/ktx/Kryos.kt",
    "chars": 1489,
    "preview": "package io.nekohasekai.sagernet.ktx\n\nimport android.os.Parcel\nimport android.os.Parcelable\nimport com.esotericsoftware.k"
  },
  {
    "path": "app/src/main/java/io/nekohasekai/sagernet/ktx/Layouts.kt",
    "chars": 2646,
    "preview": "package io.nekohasekai.sagernet.ktx\n\nimport android.graphics.Rect\nimport androidx.recyclerview.widget.LinearLayoutManage"
  },
  {
    "path": "app/src/main/java/io/nekohasekai/sagernet/ktx/Logs.kt",
    "chars": 1779,
    "preview": "package io.nekohasekai.sagernet.ktx\n\nimport libcore.Libcore\nimport java.io.InputStream\nimport java.io.OutputStream\n\nobje"
  },
  {
    "path": "app/src/main/java/io/nekohasekai/sagernet/ktx/Nets.kt",
    "chars": 1861,
    "preview": "@file:Suppress(\"SpellCheckingInspection\")\n\npackage io.nekohasekai.sagernet.ktx\n\nimport io.nekohasekai.sagernet.BuildConf"
  },
  {
    "path": "app/src/main/java/io/nekohasekai/sagernet/ktx/Preferences.kt",
    "chars": 2082,
    "preview": "package io.nekohasekai.sagernet.ktx\n\nimport androidx.preference.PreferenceDataStore\nimport kotlin.reflect.KProperty\n\nfun"
  },
  {
    "path": "app/src/main/java/io/nekohasekai/sagernet/ktx/Utils.kt",
    "chars": 11277,
    "preview": "@file:SuppressLint(\"SoonBlockedPrivateApi\")\n\npackage io.nekohasekai.sagernet.ktx\n\nimport android.animation.Animator\nimpo"
  },
  {
    "path": "app/src/main/java/io/nekohasekai/sagernet/plugin/PluginManager.kt",
    "chars": 3093,
    "preview": "package io.nekohasekai.sagernet.plugin\n\nimport android.content.pm.ComponentInfo\nimport android.content.pm.ProviderInfo\ni"
  },
  {
    "path": "app/src/main/java/io/nekohasekai/sagernet/ui/AboutFragment.kt",
    "chars": 13781,
    "preview": "package io.nekohasekai.sagernet.ui\n\nimport android.app.Activity\nimport android.content.Context\nimport android.content.In"
  },
  {
    "path": "app/src/main/java/io/nekohasekai/sagernet/ui/AppListActivity.kt",
    "chars": 12383,
    "preview": "package io.nekohasekai.sagernet.ui\n\nimport android.content.Intent\nimport android.content.pm.ApplicationInfo\nimport andro"
  },
  {
    "path": "app/src/main/java/io/nekohasekai/sagernet/ui/AppManagerActivity.kt",
    "chars": 15864,
    "preview": "package io.nekohasekai.sagernet.ui\n\nimport android.annotation.SuppressLint\nimport android.content.Intent\nimport android."
  },
  {
    "path": "app/src/main/java/io/nekohasekai/sagernet/ui/AssetsActivity.kt",
    "chars": 12052,
    "preview": "package io.nekohasekai.sagernet.ui\n\nimport android.os.Bundle\nimport android.provider.OpenableColumns\nimport android.text"
  },
  {
    "path": "app/src/main/java/io/nekohasekai/sagernet/ui/BackupFragment.kt",
    "chars": 12382,
    "preview": "package io.nekohasekai.sagernet.ui\n\nimport android.content.Intent\nimport android.net.Uri\nimport android.os.Bundle\nimport"
  },
  {
    "path": "app/src/main/java/io/nekohasekai/sagernet/ui/BlankActivity.kt",
    "chars": 464,
    "preview": "package io.nekohasekai.sagernet.ui\n\nimport android.os.Bundle\nimport androidx.appcompat.app.AppCompatActivity\nimport moe."
  },
  {
    "path": "app/src/main/java/io/nekohasekai/sagernet/ui/ConfigurationFragment.kt",
    "chars": 70414,
    "preview": "package io.nekohasekai.sagernet.ui\n\nimport android.annotation.SuppressLint\nimport android.content.Intent\nimport android."
  },
  {
    "path": "app/src/main/java/io/nekohasekai/sagernet/ui/GroupFragment.kt",
    "chars": 20580,
    "preview": "package io.nekohasekai.sagernet.ui\n\nimport android.content.Intent\nimport android.os.Bundle\nimport android.text.format.Fo"
  },
  {
    "path": "app/src/main/java/io/nekohasekai/sagernet/ui/GroupSettingsActivity.kt",
    "chars": 14532,
    "preview": "package io.nekohasekai.sagernet.ui\n\nimport android.annotation.SuppressLint\nimport android.app.Activity\nimport android.co"
  },
  {
    "path": "app/src/main/java/io/nekohasekai/sagernet/ui/LogcatFragment.kt",
    "chars": 3777,
    "preview": "package io.nekohasekai.sagernet.ui\n\nimport android.annotation.SuppressLint\nimport android.graphics.Color\nimport android."
  },
  {
    "path": "app/src/main/java/io/nekohasekai/sagernet/ui/MainActivity.kt",
    "chars": 17058,
    "preview": "package io.nekohasekai.sagernet.ui\n\nimport android.Manifest.permission.POST_NOTIFICATIONS\nimport android.annotation.Supp"
  },
  {
    "path": "app/src/main/java/io/nekohasekai/sagernet/ui/NamedFragment.kt",
    "chars": 318,
    "preview": "package io.nekohasekai.sagernet.ui\n\nimport androidx.fragment.app.Fragment\n\nabstract class NamedFragment : Fragment {\n\n  "
  },
  {
    "path": "app/src/main/java/io/nekohasekai/sagernet/ui/NetworkFragment.kt",
    "chars": 710,
    "preview": "package io.nekohasekai.sagernet.ui\n\nimport android.content.Intent\nimport android.os.Bundle\nimport android.view.View\nimpo"
  },
  {
    "path": "app/src/main/java/io/nekohasekai/sagernet/ui/ProfileSelectActivity.kt",
    "chars": 1019,
    "preview": "package io.nekohasekai.sagernet.ui\n\nimport android.content.Intent\nimport android.os.Bundle\nimport io.nekohasekai.sagerne"
  },
  {
    "path": "app/src/main/java/io/nekohasekai/sagernet/ui/QuickDisableShortcut.kt",
    "chars": 2759,
    "preview": "/*******************************************************************************\n *                                     "
  },
  {
    "path": "app/src/main/java/io/nekohasekai/sagernet/ui/QuickEnableShortcut.kt",
    "chars": 2769,
    "preview": "/*******************************************************************************\n *                                     "
  },
  {
    "path": "app/src/main/java/io/nekohasekai/sagernet/ui/RouteFragment.kt",
    "chars": 11256,
    "preview": "package io.nekohasekai.sagernet.ui\n\nimport android.content.Intent\nimport android.os.Bundle\nimport android.view.MenuItem\n"
  },
  {
    "path": "app/src/main/java/io/nekohasekai/sagernet/ui/RouteSettingsActivity.kt",
    "chars": 13232,
    "preview": "package io.nekohasekai.sagernet.ui\n\nimport android.app.Activity\nimport android.content.DialogInterface\nimport android.co"
  },
  {
    "path": "app/src/main/java/io/nekohasekai/sagernet/ui/ScannerActivity.kt",
    "chars": 7844,
    "preview": "package io.nekohasekai.sagernet.ui\n\nimport android.Manifest\nimport android.content.Intent\nimport android.content.pm.Shor"
  },
  {
    "path": "app/src/main/java/io/nekohasekai/sagernet/ui/SettingsFragment.kt",
    "chars": 691,
    "preview": "package io.nekohasekai.sagernet.ui\n\nimport android.os.Bundle\nimport android.view.View\nimport androidx.core.view.ViewComp"
  },
  {
    "path": "app/src/main/java/io/nekohasekai/sagernet/ui/SettingsPreferenceFragment.kt",
    "chars": 7754,
    "preview": "package io.nekohasekai.sagernet.ui\n\nimport android.content.Intent\nimport android.os.Build\nimport android.os.Bundle\nimpor"
  },
  {
    "path": "app/src/main/java/io/nekohasekai/sagernet/ui/StunActivity.kt",
    "chars": 2206,
    "preview": "package io.nekohasekai.sagernet.ui\n\nimport android.os.Bundle\nimport androidx.appcompat.app.AlertDialog\nimport androidx.c"
  },
  {
    "path": "app/src/main/java/io/nekohasekai/sagernet/ui/SwitchActivity.kt",
    "chars": 1117,
    "preview": "package io.nekohasekai.sagernet.ui\n\nimport android.os.Bundle\nimport io.nekohasekai.sagernet.R\nimport io.nekohasekai.sage"
  },
  {
    "path": "app/src/main/java/io/nekohasekai/sagernet/ui/ThemedActivity.kt",
    "chars": 2445,
    "preview": "package io.nekohasekai.sagernet.ui\n\nimport android.content.res.Configuration\nimport android.os.Build\nimport android.os.B"
  },
  {
    "path": "app/src/main/java/io/nekohasekai/sagernet/ui/ToolbarFragment.kt",
    "chars": 945,
    "preview": "package io.nekohasekai.sagernet.ui\n\nimport android.os.Bundle\nimport android.view.KeyEvent\nimport android.view.View\nimpor"
  },
  {
    "path": "app/src/main/java/io/nekohasekai/sagernet/ui/ToolsFragment.kt",
    "chars": 1274,
    "preview": "package io.nekohasekai.sagernet.ui\n\nimport android.os.Bundle\nimport android.view.View\nimport androidx.fragment.app.Fragm"
  },
  {
    "path": "app/src/main/java/io/nekohasekai/sagernet/ui/VpnRequestActivity.kt",
    "chars": 2779,
    "preview": "package io.nekohasekai.sagernet.ui\n\nimport android.app.Activity\nimport android.app.KeyguardManager\nimport android.conten"
  },
  {
    "path": "app/src/main/java/io/nekohasekai/sagernet/ui/WebviewFragment.kt",
    "chars": 2884,
    "preview": "package io.nekohasekai.sagernet.ui\n\nimport android.annotation.SuppressLint\nimport android.os.Bundle\nimport android.text."
  },
  {
    "path": "app/src/main/java/io/nekohasekai/sagernet/ui/profile/ChainSettingsActivity.kt",
    "chars": 10673,
    "preview": "package io.nekohasekai.sagernet.ui.profile\n\nimport android.annotation.SuppressLint\nimport android.app.Activity\nimport an"
  },
  {
    "path": "app/src/main/java/io/nekohasekai/sagernet/ui/profile/ConfigEditActivity.kt",
    "chars": 6699,
    "preview": "package io.nekohasekai.sagernet.ui.profile\n\nimport android.annotation.SuppressLint\nimport android.content.DialogInterfac"
  },
  {
    "path": "app/src/main/java/io/nekohasekai/sagernet/ui/profile/HttpSettingsActivity.kt",
    "chars": 206,
    "preview": "package io.nekohasekai.sagernet.ui.profile\n\nimport io.nekohasekai.sagernet.fmt.http.HttpBean\n\nclass HttpSettingsActivity"
  },
  {
    "path": "app/src/main/java/io/nekohasekai/sagernet/ui/profile/HysteriaSettingsActivity.kt",
    "chars": 6202,
    "preview": "package io.nekohasekai.sagernet.ui.profile\n\nimport android.os.Bundle\nimport androidx.preference.EditTextPreference\nimpor"
  },
  {
    "path": "app/src/main/java/io/nekohasekai/sagernet/ui/profile/MieruSettingsActivity.kt",
    "chars": 3614,
    "preview": "/******************************************************************************\n *                                      "
  },
  {
    "path": "app/src/main/java/io/nekohasekai/sagernet/ui/profile/NaiveSettingsActivity.kt",
    "chars": 2593,
    "preview": "package io.nekohasekai.sagernet.ui.profile\n\nimport android.os.Bundle\nimport androidx.preference.EditTextPreference\nimpor"
  },
  {
    "path": "app/src/main/java/io/nekohasekai/sagernet/ui/profile/ProfileSettingsActivity.kt",
    "chars": 15644,
    "preview": "package io.nekohasekai.sagernet.ui.profile\n\nimport android.annotation.SuppressLint\nimport android.content.DialogInterfac"
  },
  {
    "path": "app/src/main/java/io/nekohasekai/sagernet/ui/profile/SSHSettingsActivity.kt",
    "chars": 3030,
    "preview": "package io.nekohasekai.sagernet.ui.profile\n\nimport android.os.Bundle\nimport androidx.preference.EditTextPreference\nimpor"
  },
  {
    "path": "app/src/main/java/io/nekohasekai/sagernet/ui/profile/ShadowsocksSettingsActivity.kt",
    "chars": 2462,
    "preview": "package io.nekohasekai.sagernet.ui.profile\n\nimport android.os.Bundle\nimport androidx.preference.EditTextPreference\nimpor"
  },
  {
    "path": "app/src/main/java/io/nekohasekai/sagernet/ui/profile/SocksSettingsActivity.kt",
    "chars": 2233,
    "preview": "package io.nekohasekai.sagernet.ui.profile\n\nimport android.os.Bundle\nimport androidx.preference.EditTextPreference\nimpor"
  },
  {
    "path": "app/src/main/java/io/nekohasekai/sagernet/ui/profile/StandardV2RaySettingsActivity.kt",
    "chars": 8116,
    "preview": "package io.nekohasekai.sagernet.ui.profile\n\nimport android.os.Bundle\nimport androidx.preference.EditTextPreference\nimpor"
  },
  {
    "path": "app/src/main/java/io/nekohasekai/sagernet/ui/profile/TrojanGoSettingsActivity.kt",
    "chars": 4544,
    "preview": "package io.nekohasekai.sagernet.ui.profile\n\nimport android.os.Bundle\nimport androidx.preference.EditTextPreference\nimpor"
  },
  {
    "path": "app/src/main/java/io/nekohasekai/sagernet/ui/profile/TrojanSettingsActivity.kt",
    "chars": 214,
    "preview": "package io.nekohasekai.sagernet.ui.profile\n\nimport io.nekohasekai.sagernet.fmt.trojan.TrojanBean\n\nclass TrojanSettingsAc"
  },
  {
    "path": "app/src/main/java/io/nekohasekai/sagernet/ui/profile/TuicSettingsActivity.kt",
    "chars": 2525,
    "preview": "package io.nekohasekai.sagernet.ui.profile\n\nimport android.os.Bundle\nimport androidx.preference.EditTextPreference\nimpor"
  },
  {
    "path": "app/src/main/java/io/nekohasekai/sagernet/ui/profile/VMessSettingsActivity.kt",
    "chars": 321,
    "preview": "package io.nekohasekai.sagernet.ui.profile\n\nimport io.nekohasekai.sagernet.fmt.v2ray.VMessBean\n\nclass VMessSettingsActiv"
  },
  {
    "path": "app/src/main/java/io/nekohasekai/sagernet/ui/profile/WireGuardSettingsActivity.kt",
    "chars": 2134,
    "preview": "package io.nekohasekai.sagernet.ui.profile\n\nimport android.os.Bundle\nimport androidx.preference.EditTextPreference\nimpor"
  },
  {
    "path": "app/src/main/java/io/nekohasekai/sagernet/utils/Commandline.kt",
    "chars": 5330,
    "preview": "package io.nekohasekai.sagernet.utils\n\nimport java.util.*\n\n/**\n * Commandline objects help handling command lines specif"
  },
  {
    "path": "app/src/main/java/io/nekohasekai/sagernet/utils/CrashHandler.kt",
    "chars": 6408,
    "preview": "package io.nekohasekai.sagernet.utils\n\nimport android.annotation.SuppressLint\nimport android.content.Intent\nimport andro"
  },
  {
    "path": "app/src/main/java/io/nekohasekai/sagernet/utils/DefaultNetworkListener.kt",
    "chars": 6550,
    "preview": "package io.nekohasekai.sagernet.utils\n\nimport android.annotation.TargetApi\nimport android.net.ConnectivityManager\nimport"
  },
  {
    "path": "app/src/main/java/io/nekohasekai/sagernet/utils/PackageCache.kt",
    "chars": 3106,
    "preview": "package io.nekohasekai.sagernet.utils\n\nimport android.Manifest\nimport android.annotation.SuppressLint\nimport android.con"
  },
  {
    "path": "app/src/main/java/io/nekohasekai/sagernet/utils/Subnet.kt",
    "chars": 3263,
    "preview": "package io.nekohasekai.sagernet.utils\n\nimport io.nekohasekai.sagernet.ktx.parseNumericAddress\nimport java.net.InetAddres"
  },
  {
    "path": "app/src/main/java/io/nekohasekai/sagernet/utils/Theme.kt",
    "chars": 4706,
    "preview": "package io.nekohasekai.sagernet.utils\n\nimport android.content.Context\nimport android.content.res.Configuration\nimport an"
  },
  {
    "path": "app/src/main/java/io/nekohasekai/sagernet/widget/AppListPreference.kt",
    "chars": 1475,
    "preview": "package io.nekohasekai.sagernet.widget\n\nimport android.content.Context\nimport android.util.AttributeSet\nimport androidx."
  },
  {
    "path": "app/src/main/java/io/nekohasekai/sagernet/widget/AutoCollapseTextView.kt",
    "chars": 1203,
    "preview": "package io.nekohasekai.sagernet.widget\n\nimport android.annotation.SuppressLint\nimport android.content.Context\nimport and"
  },
  {
    "path": "app/src/main/java/io/nekohasekai/sagernet/widget/FabProgressBehavior.kt",
    "chars": 1048,
    "preview": "package io.nekohasekai.sagernet.widget\n\nimport android.content.Context\nimport android.util.AttributeSet\nimport android.v"
  },
  {
    "path": "app/src/main/java/io/nekohasekai/sagernet/widget/GroupPreference.kt",
    "chars": 919,
    "preview": "package io.nekohasekai.sagernet.widget\n\nimport android.content.Context\nimport android.util.AttributeSet\nimport io.nekoha"
  },
  {
    "path": "app/src/main/java/io/nekohasekai/sagernet/widget/LinkOrContentPreference.kt",
    "chars": 2292,
    "preview": "package io.nekohasekai.sagernet.widget\n\nimport android.content.Context\nimport android.net.Uri\nimport android.util.Attrib"
  },
  {
    "path": "app/src/main/java/io/nekohasekai/sagernet/widget/OutboundPreference.kt",
    "chars": 998,
    "preview": "package io.nekohasekai.sagernet.widget\n\nimport android.content.Context\nimport android.util.AttributeSet\nimport io.nekoha"
  },
  {
    "path": "app/src/main/java/io/nekohasekai/sagernet/widget/QRCodeDialog.kt",
    "chars": 3912,
    "preview": "package io.nekohasekai.sagernet.widget\n\nimport android.graphics.Bitmap\nimport android.graphics.Color\nimport android.os.B"
  },
  {
    "path": "app/src/main/java/io/nekohasekai/sagernet/widget/ServiceButton.kt",
    "chars": 5823,
    "preview": "package io.nekohasekai.sagernet.widget\n\nimport android.content.Context\nimport android.graphics.drawable.Drawable\nimport "
  },
  {
    "path": "app/src/main/java/io/nekohasekai/sagernet/widget/StatsBar.kt",
    "chars": 5301,
    "preview": "package io.nekohasekai.sagernet.widget\n\nimport android.annotation.SuppressLint\nimport android.content.Context\nimport and"
  },
  {
    "path": "app/src/main/java/io/nekohasekai/sagernet/widget/UndoSnackbarManager.kt",
    "chars": 1714,
    "preview": "package io.nekohasekai.sagernet.widget\n\nimport com.google.android.material.snackbar.Snackbar\nimport io.nekohasekai.sager"
  },
  {
    "path": "app/src/main/java/io/nekohasekai/sagernet/widget/UserAgentPreference.kt",
    "chars": 814,
    "preview": "package io.nekohasekai.sagernet.widget\n\nimport android.content.Context\nimport android.util.AttributeSet\nimport androidx."
  },
  {
    "path": "app/src/main/java/io/nekohasekai/sagernet/widget/WindowInsetsListeners.kt",
    "chars": 462,
    "preview": "package io.nekohasekai.sagernet.widget\n\nimport android.view.View\nimport androidx.core.view.OnApplyWindowInsetsListener\ni"
  },
  {
    "path": "app/src/main/java/moe/matsuri/nb4a/NativeInterface.kt",
    "chars": 3675,
    "preview": "package moe.matsuri.nb4a\n\nimport android.content.Context\nimport android.net.ConnectivityManager\nimport android.net.wifi."
  },
  {
    "path": "app/src/main/java/moe/matsuri/nb4a/Protocols.kt",
    "chars": 1780,
    "preview": "package moe.matsuri.nb4a\n\nimport android.content.Context\nimport io.nekohasekai.sagernet.R\nimport io.nekohasekai.sagernet"
  },
  {
    "path": "app/src/main/java/moe/matsuri/nb4a/SingBoxOptions.java",
    "chars": 99479,
    "preview": "package moe.matsuri.nb4a;\n\nimport com.google.gson.Gson;\nimport com.google.gson.GsonBuilder;\nimport com.google.gson.JsonE"
  },
  {
    "path": "app/src/main/java/moe/matsuri/nb4a/SingBoxOptionsUtil.kt",
    "chars": 6027,
    "preview": "package moe.matsuri.nb4a\n\nimport io.nekohasekai.sagernet.database.DataStore\nimport moe.matsuri.nb4a.SingBoxOptions.RuleS"
  },
  {
    "path": "app/src/main/java/moe/matsuri/nb4a/TempDatabase.kt",
    "chars": 915,
    "preview": "package moe.matsuri.nb4a\n\nimport androidx.room.Database\nimport androidx.room.Room\nimport androidx.room.RoomDatabase\nimpo"
  },
  {
    "path": "app/src/main/java/moe/matsuri/nb4a/net/LocalResolverImpl.kt",
    "chars": 5120,
    "preview": "package moe.matsuri.nb4a.net\n\nimport android.net.DnsResolver\nimport android.os.Build\nimport android.os.CancellationSigna"
  },
  {
    "path": "app/src/main/java/moe/matsuri/nb4a/plugin/Plugins.kt",
    "chars": 4217,
    "preview": "package moe.matsuri.nb4a.plugin\n\nimport android.content.Intent\nimport android.content.pm.PackageInfo\nimport android.cont"
  },
  {
    "path": "app/src/main/java/moe/matsuri/nb4a/proxy/PreferenceBinding.kt",
    "chars": 2985,
    "preview": "package moe.matsuri.nb4a.proxy\n\nimport androidx.preference.Preference\nimport androidx.preference.PreferenceFragmentCompa"
  },
  {
    "path": "app/src/main/java/moe/matsuri/nb4a/proxy/PreferenceBindingManager.kt",
    "chars": 663,
    "preview": "package moe.matsuri.nb4a.proxy\n\nimport androidx.preference.PreferenceFragmentCompat\n\n\nclass PreferenceBindingManager {\n "
  },
  {
    "path": "app/src/main/java/moe/matsuri/nb4a/proxy/anytls/AnyTLSBean.java",
    "chars": 2605,
    "preview": "package moe.matsuri.nb4a.proxy.anytls;\n\nimport androidx.annotation.NonNull;\n\nimport com.esotericsoftware.kryo.io.ByteBuf"
  },
  {
    "path": "app/src/main/java/moe/matsuri/nb4a/proxy/anytls/AnyTLSFmt.kt",
    "chars": 2743,
    "preview": "package moe.matsuri.nb4a.proxy.anytls\n\nimport io.nekohasekai.sagernet.ktx.blankAsNull\nimport io.nekohasekai.sagernet.ktx"
  },
  {
    "path": "app/src/main/java/moe/matsuri/nb4a/proxy/anytls/AnyTLSSettingsActivity.kt",
    "chars": 2117,
    "preview": "package moe.matsuri.nb4a.proxy.anytls\n\nimport android.os.Bundle\nimport androidx.preference.EditTextPreference\nimport and"
  },
  {
    "path": "app/src/main/java/moe/matsuri/nb4a/proxy/config/ConfigBean.java",
    "chars": 2344,
    "preview": "package moe.matsuri.nb4a.proxy.config;\n\nimport androidx.annotation.NonNull;\n\nimport com.esotericsoftware.kryo.io.ByteBuf"
  },
  {
    "path": "app/src/main/java/moe/matsuri/nb4a/proxy/config/ConfigSettingActivity.kt",
    "chars": 1876,
    "preview": "package moe.matsuri.nb4a.proxy.config\n\nimport android.os.Bundle\nimport androidx.preference.PreferenceDataStore\nimport an"
  },
  {
    "path": "app/src/main/java/moe/matsuri/nb4a/proxy/neko/NekoBean.java",
    "chars": 2383,
    "preview": "package moe.matsuri.nb4a.proxy.neko;\n\nimport androidx.annotation.NonNull;\n\nimport com.esotericsoftware.kryo.io.ByteBuffe"
  },
  {
    "path": "app/src/main/java/moe/matsuri/nb4a/proxy/shadowtls/ShadowTLSBean.java",
    "chars": 1622,
    "preview": "package moe.matsuri.nb4a.proxy.shadowtls;\n\nimport androidx.annotation.NonNull;\n\nimport com.esotericsoftware.kryo.io.Byte"
  },
  {
    "path": "app/src/main/java/moe/matsuri/nb4a/proxy/shadowtls/ShadowTLSFmt.kt",
    "chars": 529,
    "preview": "package moe.matsuri.nb4a.proxy.shadowtls\n\nimport io.nekohasekai.sagernet.fmt.v2ray.buildSingBoxOutboundTLS\nimport moe.ma"
  },
  {
    "path": "app/src/main/java/moe/matsuri/nb4a/proxy/shadowtls/ShadowTLSSettingsActivity.kt",
    "chars": 2168,
    "preview": "package moe.matsuri.nb4a.proxy.shadowtls\n\nimport android.os.Bundle\nimport androidx.preference.EditTextPreference\nimport "
  },
  {
    "path": "app/src/main/java/moe/matsuri/nb4a/ui/ColorPickerPreference.kt",
    "chars": 3714,
    "preview": "package moe.matsuri.nb4a.ui\n\nimport android.content.Context\nimport android.content.res.Resources\nimport android.graphics"
  }
]

// ... and 324 more files (download for full content)

About this extraction

This page contains the full source code of the MatsuriDayo/NekoBoxForAndroid GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 524 files (1.8 MB), approximately 475.5k tokens, and a symbol index with 683 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.

Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.

Copied to clipboard!