├── .gitignore
├── LICENSE
├── README.md
├── app
├── .gitignore
├── build.gradle
├── libs
│ ├── arm64-v8a
│ │ └── libtun2socks.so
│ ├── armeabi-v7a
│ │ └── libtun2socks.so
│ ├── x86
│ │ └── libtun2socks.so
│ └── x86_64
│ │ └── libtun2socks.so
├── proguard-rules.pro
└── src
│ ├── androidTest
│ └── java
│ │ └── com
│ │ └── agn
│ │ └── v2ray
│ │ └── ApplicationTest.java
│ ├── dev
│ └── res
│ │ └── values
│ │ └── strings.xml
│ ├── main
│ ├── AndroidManifest.xml
│ ├── assets
│ │ ├── custom_routing_block
│ │ ├── custom_routing_direct
│ │ ├── custom_routing_proxy
│ │ ├── proxy_packagename.txt
│ │ └── v2ray_config.json
│ ├── java
│ │ └── com
│ │ │ └── agn
│ │ │ └── v2ray
│ │ │ ├── ThemeSettings.java
│ │ │ └── helper
│ │ │ ├── ItemTouchHelperAdapter.java
│ │ │ ├── ItemTouchHelperViewHolder.java
│ │ │ ├── OnStartDragListener.java
│ │ │ └── SimpleItemTouchHelperCallback.java
│ ├── kotlin
│ │ └── com
│ │ │ └── agn
│ │ │ └── v2ray
│ │ │ ├── AngApplication.kt
│ │ │ ├── AppConfig.kt
│ │ │ ├── SplashActivity.kt
│ │ │ ├── dto
│ │ │ ├── AngConfig.kt
│ │ │ ├── AppInfo.kt
│ │ │ ├── EConfigType.kt
│ │ │ ├── ERoutingMode.kt
│ │ │ ├── ServerAffiliationInfo.kt
│ │ │ ├── ServerConfig.kt
│ │ │ ├── ServersCache.kt
│ │ │ ├── SubscriptionItem.kt
│ │ │ ├── V2rayConfig.kt
│ │ │ └── VmessQRCode.kt
│ │ │ ├── extension
│ │ │ └── _Ext.kt
│ │ │ ├── receiver
│ │ │ ├── TaskerReceiver.kt
│ │ │ └── WidgetProvider.kt
│ │ │ ├── service
│ │ │ ├── QSTileService.kt
│ │ │ ├── ServiceControl.kt
│ │ │ ├── SubscriptionUpdater.kt
│ │ │ ├── V2RayProxyOnlyService.kt
│ │ │ ├── V2RayServiceManager.kt
│ │ │ ├── V2RayTestService.kt
│ │ │ └── V2RayVpnService.kt
│ │ │ ├── ui
│ │ │ ├── AboutActivity.kt
│ │ │ ├── BaseActivity.kt
│ │ │ ├── FragmentAdapter.kt
│ │ │ ├── LogcatActivity.kt
│ │ │ ├── MainActivity.kt
│ │ │ ├── MainRecyclerAdapter.kt
│ │ │ ├── PerAppProxyActivity.kt
│ │ │ ├── PerAppProxyAdapter.kt
│ │ │ ├── RoutingSettingsActivity.kt
│ │ │ ├── RoutingSettingsFragment.kt
│ │ │ ├── ScScannerActivity.kt
│ │ │ ├── ScSwitchActivity.kt
│ │ │ ├── ScannerActivity.kt
│ │ │ ├── ServerActivity.kt
│ │ │ ├── ServerCustomConfigActivity.kt
│ │ │ ├── SettingsActivity.kt
│ │ │ ├── SubEditActivity.kt
│ │ │ ├── SubSettingActivity.kt
│ │ │ ├── SubSettingRecyclerAdapter.kt
│ │ │ ├── TaskerActivity.kt
│ │ │ ├── UrlSchemeActivity.kt
│ │ │ └── UserAssetActivity.kt
│ │ │ ├── util
│ │ │ ├── AngConfigManager.kt
│ │ │ ├── AppManagerUtil.kt
│ │ │ ├── LanguageHelper.kt
│ │ │ ├── LanguagePrefs.kt
│ │ │ ├── MessageUtil.kt
│ │ │ ├── MmkvManager.kt
│ │ │ ├── MyContextWrapper.kt
│ │ │ ├── QRCodeDecoder.kt
│ │ │ ├── SpeedtestUtil.kt
│ │ │ ├── Utils.kt
│ │ │ └── V2rayConfigUtil.kt
│ │ │ └── viewmodel
│ │ │ ├── MainViewModel.kt
│ │ │ └── SettingsViewModel.kt
│ └── res
│ │ ├── anim
│ │ ├── fade_in.xml
│ │ └── fade_out.xml
│ │ ├── color
│ │ └── color_highlight_material.xml
│ │ ├── drawable-hdpi
│ │ ├── ic_stat_direct.png
│ │ ├── ic_stat_name.png
│ │ └── ic_stat_proxy.png
│ │ ├── drawable-ldrtl
│ │ └── bg_nav.xml
│ │ ├── drawable-mdpi
│ │ ├── ic_stat_direct.png
│ │ ├── ic_stat_name.png
│ │ └── ic_stat_proxy.png
│ │ ├── drawable-xhdpi
│ │ ├── ic_stat_direct.png
│ │ ├── ic_stat_name.png
│ │ └── ic_stat_proxy.png
│ │ ├── drawable-xxhdpi
│ │ ├── donate.png
│ │ ├── ic_stat_direct.png
│ │ ├── ic_stat_name.png
│ │ ├── ic_stat_proxy.png
│ │ └── side_nav_bar.xml
│ │ ├── drawable-xxxhdpi
│ │ ├── ic_stat_direct.png
│ │ ├── ic_stat_name.png
│ │ └── ic_stat_proxy.png
│ │ ├── drawable
│ │ ├── autorenew.xml
│ │ ├── background_test_button.xml
│ │ ├── baseline_privacy_tip_24.xml
│ │ ├── bg_nav.xml
│ │ ├── ic_action_done.xml
│ │ ├── ic_action_done_white.xml
│ │ ├── ic_add_black_24dp.xml
│ │ ├── ic_add_white_24dp.xml
│ │ ├── ic_attach_money_black_24dp.xml
│ │ ├── ic_attach_money_white_24dp.xml
│ │ ├── ic_autorenew_black_24dp.png
│ │ ├── ic_baseline_add_24.xml
│ │ ├── ic_baseline_arrow_back_24.xml
│ │ ├── ic_baseline_filter_alt_24.xml
│ │ ├── ic_close_grey_800_24dp.xml
│ │ ├── ic_cloud_download_white_24dp.xml
│ │ ├── ic_copy_white.xml
│ │ ├── ic_delete_black_24dp.xml
│ │ ├── ic_delete_white_24dp.xml
│ │ ├── ic_description_black_24dp.xml
│ │ ├── ic_description_white_24dp.xml
│ │ ├── ic_edit_black_24dp.xml
│ │ ├── ic_fab_check.xml
│ │ ├── ic_fab_uncheck.png
│ │ ├── ic_feedback_white_24dp.xml
│ │ ├── ic_file_white_24dp.xml
│ │ ├── ic_image_photo.xml
│ │ ├── ic_info.xml
│ │ ├── ic_info_black_24dp.xml
│ │ ├── ic_logcat_white_24dp.xml
│ │ ├── ic_outline_filter_alt_white_24.xml
│ │ ├── ic_person.xml
│ │ ├── ic_plane.xml
│ │ ├── ic_qu_scan_black_24dp.xml
│ │ ├── ic_qu_settings_black_24dp.xml
│ │ ├── ic_qu_switch_black_24dp.xml
│ │ ├── ic_rounded_corner_grey.xml
│ │ ├── ic_rounded_corner_theme.xml
│ │ ├── ic_save_white_24dp.xml
│ │ ├── ic_scan_black_24dp.xml
│ │ ├── ic_select_all_white_24dp.xml
│ │ ├── ic_settings_white_24dp.xml
│ │ ├── ic_share_black_24dp.xml
│ │ ├── ic_share_white_24dp.xml
│ │ ├── ic_shortcut_background.xml
│ │ ├── ic_start_busy.xml
│ │ ├── ic_start_connected.xml
│ │ ├── ic_start_connected_black.xml
│ │ ├── ic_start_idle.xml
│ │ ├── ic_stat_direct.png
│ │ ├── ic_stat_proxy.png
│ │ ├── ic_subscriptions_black_24dp.xml
│ │ ├── ic_subscriptions_white_24dp.xml
│ │ ├── ic_v.png
│ │ ├── ic_v_connected_black.xml
│ │ ├── ic_v_idle.png
│ │ ├── ic_whatshot_black_24dp.xml
│ │ ├── ic_whatshot_white_24dp.xml
│ │ ├── ic_youtube.png
│ │ ├── icon.png
│ │ └── nav_header_bg.png
│ │ ├── font
│ │ └── poppins_medium.ttf
│ │ ├── layout
│ │ ├── .activity_main.xml.kate-swp
│ │ ├── activity_about.xml
│ │ ├── activity_bypass_list.xml
│ │ ├── activity_logcat.xml
│ │ ├── activity_main.xml
│ │ ├── activity_none.xml
│ │ ├── activity_routing_settings.xml
│ │ ├── activity_server_custom_config.xml
│ │ ├── activity_server_shadowsocks.xml
│ │ ├── activity_server_socks.xml
│ │ ├── activity_server_trojan.xml
│ │ ├── activity_server_vless.xml
│ │ ├── activity_server_vmess.xml
│ │ ├── activity_settings.xml
│ │ ├── activity_splash.xml
│ │ ├── activity_sub_edit.xml
│ │ ├── activity_sub_setting.xml
│ │ ├── activity_tasker.xml
│ │ ├── daynightswitch.xml
│ │ ├── dialog_config_filter.xml
│ │ ├── fragment_routing_settings.xml
│ │ ├── item_qrcode.xml
│ │ ├── item_recycler_bypass_list.xml
│ │ ├── item_recycler_footer.xml
│ │ ├── item_recycler_main.xml
│ │ ├── item_recycler_sub_setting.xml
│ │ ├── item_recycler_user_asset.xml
│ │ ├── nav_header.xml
│ │ ├── nav_toolbar.xml
│ │ ├── nav_view.xml
│ │ ├── preference_with_help_link.xml
│ │ ├── tls_layout.xml
│ │ └── widget_switch.xml
│ │ ├── menu
│ │ ├── action_server.xml
│ │ ├── action_sub_setting.xml
│ │ ├── menu_asset.xml
│ │ ├── menu_bypass_list.xml
│ │ ├── menu_drawer.xml
│ │ ├── menu_logcat.xml
│ │ ├── menu_main.xml
│ │ ├── menu_routing.xml
│ │ └── menu_scanner.xml
│ │ ├── raw
│ │ └── licenses.xml
│ │ ├── values-ar
│ │ └── strings.xml
│ │ ├── values-de
│ │ └── strings.xml
│ │ ├── values-es
│ │ └── strings.xml
│ │ ├── values-fa
│ │ └── strings.xml
│ │ ├── values-fr
│ │ └── strings.xml
│ │ ├── values-lt
│ │ └── strings.xml
│ │ ├── values-night
│ │ └── colors.xml
│ │ ├── values-pt
│ │ └── strings.xml
│ │ ├── values-ru
│ │ └── strings.xml
│ │ ├── values-sw360dp-v13
│ │ └── values-preference.xml
│ │ ├── values-th
│ │ └── strings.xml
│ │ ├── values-vi
│ │ └── strings.xml
│ │ ├── values-zh-rCN
│ │ └── strings.xml
│ │ ├── values-zh-rTW
│ │ └── strings.xml
│ │ ├── values
│ │ ├── arrays.xml
│ │ ├── attrs.xml
│ │ ├── colors.xml
│ │ ├── dimens.xml
│ │ ├── ic_launcher_background.xml
│ │ ├── strings.xml
│ │ └── styles.xml
│ │ └── xml
│ │ ├── app_widget_provider.xml
│ │ ├── pref_settings.xml
│ │ └── shortcuts.xml
│ └── test
│ ├── java
│ └── com
│ │ └── agn
│ │ └── v2ray
│ │ └── ExampleUnitTest.java
│ └── kotlin
│ └── com
│ └── agn
│ └── v2ray
│ └── ExampleUnitTest.kt
├── build.gradle
├── daynightswitch
├── .gitignore
├── build.gradle
├── proguard-rules.pro
└── src
│ └── main
│ ├── AndroidManifest.xml
│ ├── java
│ └── com
│ │ └── agn
│ │ └── daynightswitch
│ │ ├── DayNightSwitch.java
│ │ ├── DayNightSwitchAnimListener.java
│ │ └── DayNightSwitchListener.java
│ └── res
│ ├── drawable-hdpi
│ ├── dark_background.png
│ ├── img_clouds.png
│ ├── img_moon.png
│ └── img_sun.png
│ ├── drawable-ldpi
│ ├── dark_background.png
│ ├── img_clouds.png
│ ├── img_moon.png
│ └── img_sun.png
│ ├── drawable-mdpi
│ ├── dark_background.png
│ ├── img_clouds.png
│ ├── img_moon.png
│ └── img_sun.png
│ ├── drawable-xhdpi
│ ├── dark_background.png
│ ├── img_clouds.png
│ ├── img_moon.png
│ └── img_sun.png
│ ├── drawable-xxhdpi
│ ├── dark_background.png
│ ├── img_clouds.png
│ ├── img_moon.png
│ └── img_sun.png
│ ├── drawable-xxxhdpi
│ ├── dark_background.png
│ ├── img_clouds.png
│ ├── img_moon.png
│ └── img_sun.png
│ └── values
│ ├── colors.xml
│ └── strings.xml
├── gradle.properties
├── gradle
└── wrapper
│ ├── gradle-wrapper.jar
│ └── gradle-wrapper.properties
├── gradlew
├── gradlew.bat
└── settings.gradle
/.gitignore:
--------------------------------------------------------------------------------
1 | *.iml
2 | .gradle
3 | /local.properties
4 | /.idea
5 | .DS_Store
6 | /build
7 | /captures
8 | *.apk
9 | signing.properties
10 | *.aar
11 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # V2rayAGN - Enhanced V2Ray Client for Android
2 |
3 |
4 |
5 | #### Introduction
6 |
7 | Welcome to V2rayAGN, an advanced and user-friendly V2Ray client for Android devices, based on the popular [v2rayNG](https://github.com/2dust/v2rayNG) codebase. Our app is designed to provide a seamless and secure browsing experience, now with added features and improvements for an even better user experience.
8 |
9 | #### Features
10 |
11 | - Dark Mode: A sleek and eye-friendly interface for nighttime browsing.
12 | - Improved Language Selection: Enhanced multilingual support for a global user base.
13 | - Beautiful UI: A revamped, modern, and intuitive user interface.
14 | - Core V2Ray Functionality: All the robust features from v2rayNG, including VMess, Shadowsocks, and more.
15 | - Play Store Availability: Easy to download and update through the Google Play Store.
16 |
17 |
18 | # Getting Started
19 |
20 | #### Prerequisites
21 |
22 | - Android 5.0 or higher.
23 | - Active internet connection.
24 |
25 | #### Installation
26 |
27 | Download the app directly from the Google Play Store:
28 |
29 |
30 |
31 |
32 |
33 | #### Usage
34 |
35 | - Open V2rayAGN.
36 | - Configure your server settings or import from a pre-existing configuration.
37 | - Connect and enjoy secure and private browsing.
38 |
39 | # Feedback and Support
40 |
41 | For support or bug reporting, please open an issue in the GitHub repository.
42 |
43 |
44 | # License
45 |
46 | This project is licensed under [GPL-3.0] - see the [LICENSE](https://github.com/khaledagn/V2rayAGN/blob/main/LICENSE) file for details.
47 |
48 |
49 | # Acknowledgments
50 |
51 | Thanks to the creators of [v2rayNG](https://github.com/2dust/v2rayNG) for their foundational work.
52 |
--------------------------------------------------------------------------------
/app/.gitignore:
--------------------------------------------------------------------------------
1 | /build
2 | /google-services.json
3 |
--------------------------------------------------------------------------------
/app/libs/arm64-v8a/libtun2socks.so:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/khaledagn/V2rayAGN/f348cb956337c1f9cbcc553f4beb0cf0c9f9bed8/app/libs/arm64-v8a/libtun2socks.so
--------------------------------------------------------------------------------
/app/libs/armeabi-v7a/libtun2socks.so:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/khaledagn/V2rayAGN/f348cb956337c1f9cbcc553f4beb0cf0c9f9bed8/app/libs/armeabi-v7a/libtun2socks.so
--------------------------------------------------------------------------------
/app/libs/x86/libtun2socks.so:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/khaledagn/V2rayAGN/f348cb956337c1f9cbcc553f4beb0cf0c9f9bed8/app/libs/x86/libtun2socks.so
--------------------------------------------------------------------------------
/app/libs/x86_64/libtun2socks.so:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/khaledagn/V2rayAGN/f348cb956337c1f9cbcc553f4beb0cf0c9f9bed8/app/libs/x86_64/libtun2socks.so
--------------------------------------------------------------------------------
/app/proguard-rules.pro:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/khaledagn/V2rayAGN/f348cb956337c1f9cbcc553f4beb0cf0c9f9bed8/app/proguard-rules.pro
--------------------------------------------------------------------------------
/app/src/androidTest/java/com/agn/v2ray/ApplicationTest.java:
--------------------------------------------------------------------------------
1 | package com.agn.v2ray;
2 |
3 | import android.app.Application;
4 | import android.test.ApplicationTestCase;
5 |
6 | /**
7 | * Testing Fundamentals
8 | */
9 | public class ApplicationTest extends ApplicationTestCase {
10 | public ApplicationTest() {
11 | super(Application.class);
12 | }
13 | }
--------------------------------------------------------------------------------
/app/src/dev/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | V2rayAGN
4 |
--------------------------------------------------------------------------------
/app/src/main/assets/custom_routing_block:
--------------------------------------------------------------------------------
1 | geosite:category-ads-all,
--------------------------------------------------------------------------------
/app/src/main/assets/custom_routing_direct:
--------------------------------------------------------------------------------
1 | domain:12306.com,
2 | domain:51ym.me,
3 | domain:52pojie.cn,
4 | domain:8686c.com,
5 | domain:abercrombie.com,
6 | domain:adobesc.com,
7 | domain:air-matters.com,
8 | domain:air-matters.io,
9 | domain:airtable.com,
10 | domain:akadns.net,
11 | domain:apache.org,
12 | domain:api.crisp.chat,
13 | domain:api.termius.com,
14 | domain:appshike.com,
15 | domain:appstore.com,
16 | domain:aweme.snssdk.com,
17 | domain:bababian.com,
18 | domain:battle.net,
19 | domain:beatsbydre.com,
20 | domain:bet365.com,
21 | domain:bilibili.cn,
22 | domain:ccgslb.com,
23 | domain:ccgslb.net,
24 | domain:chunbo.com,
25 | domain:chunboimg.com,
26 | domain:clashroyaleapp.com,
27 | domain:cloudsigma.com,
28 | domain:cloudxns.net,
29 | domain:cmfu.com,
30 | domain:culturedcode.com,
31 | domain:dct-cloud.com,
32 | domain:didialift.com,
33 | domain:douyutv.com,
34 | domain:duokan.com,
35 | domain:dytt8.net,
36 | domain:easou.com,
37 | domain:ecitic.net,
38 | domain:eclipse.org,
39 | domain:eudic.net,
40 | domain:ewqcxz.com,
41 | domain:fir.im,
42 | domain:frdic.com,
43 | domain:fresh-ideas.cc,
44 | domain:godic.net,
45 | domain:goodread.com,
46 | domain:haibian.com,
47 | domain:hdslb.net,
48 | domain:hollisterco.com,
49 | domain:hongxiu.com,
50 | domain:hxcdn.net,
51 | domain:images.unsplash.com,
52 | domain:img4me.com,
53 | domain:ipify.org,
54 | domain:ixdzs.com,
55 | domain:jd.hk,
56 | domain:jianshuapi.com,
57 | domain:jomodns.com,
58 | domain:jsboxbbs.com,
59 | domain:knewone.com,
60 | domain:kuaidi100.com,
61 | domain:lemicp.com,
62 | domain:letvcloud.com,
63 | domain:lizhi.io,
64 | domain:localizecdn.com,
65 | domain:lucifr.com,
66 | domain:luoo.net,
67 | domain:mai.tn,
68 | domain:maven.org,
69 | domain:miwifi.com,
70 | domain:moji.com,
71 | domain:moke.com,
72 | domain:mtalk.google.com,
73 | domain:mxhichina.com,
74 | domain:myqcloud.com,
75 | domain:myunlu.com,
76 | domain:netease.com,
77 | domain:nfoservers.com,
78 | domain:nssurge.com,
79 | domain:nuomi.com,
80 | domain:ourdvs.com,
81 | domain:overcast.fm,
82 | domain:paypal.com,
83 | domain:paypalobjects.com,
84 | domain:pgyer.com,
85 | domain:qdaily.com,
86 | domain:qdmm.com,
87 | domain:qin.io,
88 | domain:qingmang.me,
89 | domain:qingmang.mobi,
90 | domain:qqurl.com,
91 | domain:rarbg.to,
92 | domain:rrmj.tv,
93 | domain:ruguoapp.com,
94 | domain:sm.ms,
95 | domain:snwx.com,
96 | domain:soku.com,
97 | domain:startssl.com,
98 | domain:store.steampowered.com,
99 | domain:symcd.com,
100 | domain:teamviewer.com,
101 | domain:tmzvps.com,
102 | domain:trello.com,
103 | domain:trellocdn.com,
104 | domain:ttmeiju.com,
105 | domain:udache.com,
106 | domain:uxengine.net,
107 | domain:weather.bjango.com,
108 | domain:weather.com,
109 | domain:webqxs.com,
110 | domain:weico.cc,
111 | domain:wenku8.net,
112 | domain:werewolf.53site.com,
113 | domain:windowsupdate.com,
114 | domain:wkcdn.com,
115 | domain:workflowy.com,
116 | domain:xdrig.com,
117 | domain:xiaojukeji.com,
118 | domain:xiaomi.net,
119 | domain:xiaomicp.com,
120 | domain:ximalaya.com,
121 | domain:xitek.com,
122 | domain:xmcdn.com,
123 | domain:xslb.net,
124 | domain:xteko.com,
125 | domain:yach.me,
126 | domain:yixia.com,
127 | domain:yunjiasu-cdn.net,
128 | domain:zealer.com,
129 | domain:zgslb.net,
130 | domain:zimuzu.tv,
131 | domain:zmz002.com,
132 | domain:samsungdm.com,
--------------------------------------------------------------------------------
/app/src/main/assets/custom_routing_proxy:
--------------------------------------------------------------------------------
1 | geosite:google,
2 | geosite:github,
3 | geosite:netflix,
4 | geosite:steam,
5 | geosite:telegram,
6 | geosite:tumblr,
7 | geosite:speedtest,
8 | geosite:bbc,
9 | domain:gvt1.com,
10 | domain:textnow.com,
11 | domain:twitch.tv,
12 | domain:wikileaks.org,
13 | domain:naver.com,
14 | 91.108.4.0/22,
15 | 91.108.8.0/22,
16 | 91.108.12.0/22,
17 | 91.108.20.0/22,
18 | 91.108.36.0/23,
19 | 91.108.38.0/23,
20 | 91.108.56.0/22,
21 | 149.154.160.0/20,
22 | 149.154.164.0/22,
23 | 149.154.172.0/22,
24 | 74.125.0.0/16,
25 | 173.194.0.0/16,
26 | 172.217.0.0/16,
27 | 216.58.200.0/24,
28 | 216.58.220.0/24,
29 | 91.108.56.116,
30 | 91.108.56.0/24,
31 | 109.239.140.0/24,
32 | 149.154.167.0/24,
33 | 149.154.175.0/24,
--------------------------------------------------------------------------------
/app/src/main/assets/v2ray_config.json:
--------------------------------------------------------------------------------
1 | {
2 | "stats":{},
3 | "log": {
4 | "loglevel": "warning"
5 | },
6 | "policy":{
7 | "levels": {
8 | "8": {
9 | "handshake": 4,
10 | "connIdle": 300,
11 | "uplinkOnly": 1,
12 | "downlinkOnly": 1
13 | }
14 | },
15 | "system": {
16 | "statsOutboundUplink": true,
17 | "statsOutboundDownlink": true
18 | }
19 | },
20 | "inbounds": [{
21 | "tag": "socks",
22 | "port": 10808,
23 | "protocol": "socks",
24 | "settings": {
25 | "auth": "noauth",
26 | "udp": true,
27 | "userLevel": 8
28 | },
29 | "sniffing": {
30 | "enabled": true,
31 | "destOverride": [
32 | "http",
33 | "tls"
34 | ]
35 | }
36 | },
37 | {
38 | "tag": "http",
39 | "port": 10809,
40 | "protocol": "http",
41 | "settings": {
42 | "userLevel": 8
43 | }
44 | }
45 | ],
46 | "outbounds": [{
47 | "tag": "proxy",
48 | "protocol": "vmess",
49 | "settings": {
50 | "vnext": [
51 | {
52 | "address": "v2ray.cool",
53 | "port": 10086,
54 | "users": [
55 | {
56 | "id": "a3482e88-686a-4a58-8126-99c9df64b7bf",
57 | "alterId": 0,
58 | "security": "auto",
59 | "level": 8
60 | }
61 | ]
62 | }
63 | ],
64 | "servers": [
65 | {
66 | "address": "v2ray.cool",
67 | "method": "chacha20",
68 | "ota": false,
69 | "password": "123456",
70 | "port": 10086,
71 | "level": 8
72 | }
73 | ]
74 | },
75 | "streamSettings": {
76 | "network": "tcp"
77 | },
78 | "mux": {
79 | "enabled": false
80 | }
81 | },
82 | {
83 | "protocol": "freedom",
84 | "settings": {},
85 | "tag": "direct"
86 | },
87 | {
88 | "protocol": "blackhole",
89 | "tag": "block",
90 | "settings": {
91 | "response": {
92 | "type": "http"
93 | }
94 | }
95 | }
96 | ],
97 | "routing": {
98 | "domainStrategy": "IPIfNonMatch",
99 | "rules": []
100 | },
101 | "dns": {
102 | "hosts": {},
103 | "servers": []
104 | }
105 | }
106 |
--------------------------------------------------------------------------------
/app/src/main/java/com/agn/v2ray/ThemeSettings.java:
--------------------------------------------------------------------------------
1 | package com.agn.v2ray;
2 |
3 | import android.content.Context;
4 | import android.content.SharedPreferences;
5 | import androidx.appcompat.app.AppCompatDelegate;
6 |
7 |
8 | public class ThemeSettings {
9 |
10 | private static ThemeSettings instance;
11 |
12 | public static ThemeSettings getInstance(Context context) {
13 | if (instance == null) instance = new ThemeSettings(context);
14 | return instance;
15 | }
16 |
17 | private static class Key {
18 | private static final String NIGHT_MODE = "nightMode";
19 | }
20 |
21 | public boolean nightMode;
22 |
23 | private ThemeSettings(Context context) {
24 | SharedPreferences prefs = context.getSharedPreferences("settings", Context.MODE_PRIVATE);
25 | nightMode = prefs.getBoolean(Key.NIGHT_MODE, false);
26 | }
27 |
28 | public void save(Context context) {
29 | SharedPreferences.Editor editor = context.getSharedPreferences("settings", Context.MODE_PRIVATE).edit();
30 | editor.putBoolean(Key.NIGHT_MODE, nightMode);
31 | editor.apply();
32 | }
33 |
34 | public void refreshTheme() {
35 | AppCompatDelegate.setDefaultNightMode(nightMode ?
36 | AppCompatDelegate.MODE_NIGHT_YES :
37 | AppCompatDelegate.MODE_NIGHT_NO);
38 | }
39 | }
40 |
--------------------------------------------------------------------------------
/app/src/main/java/com/agn/v2ray/helper/ItemTouchHelperAdapter.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2015 Paul Burke
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package com.agn.v2ray.helper;
18 |
19 | import androidx.recyclerview.widget.RecyclerView;
20 | import androidx.recyclerview.widget.ItemTouchHelper;
21 |
22 | /**
23 | * Interface to listen for a move or dismissal event from a {@link ItemTouchHelper.Callback}.
24 | *
25 | * @author Paul Burke (ipaulpro)
26 | */
27 | public interface ItemTouchHelperAdapter {
28 |
29 | /**
30 | * Called when an item has been dragged far enough to trigger a move. This is called every time
31 | * an item is shifted, and not at the end of a "drop" event.
32 | *
33 | * Implementations should call {@link RecyclerView.Adapter#notifyItemMoved(int, int)} after
34 | * adjusting the underlying data to reflect this move.
35 | *
36 | * @param fromPosition The start position of the moved item.
37 | * @param toPosition Then resolved position of the moved item.
38 | * @return True if the item was moved to the new adapter position.
39 | *
40 | * @see RecyclerView#getAdapterPositionFor(RecyclerView.ViewHolder)
41 | * @see RecyclerView.ViewHolder#getAdapterPosition()
42 | */
43 | boolean onItemMove(int fromPosition, int toPosition);
44 |
45 |
46 | void onItemMoveCompleted();
47 |
48 | /**
49 | * Called when an item has been dismissed by a swipe.
50 | *
51 | * Implementations should call {@link RecyclerView.Adapter#notifyItemRemoved(int)} after
52 | * adjusting the underlying data to reflect this removal.
53 | *
54 | * @param position The position of the item dismissed.
55 | *
56 | * @see RecyclerView#getAdapterPositionFor(RecyclerView.ViewHolder)
57 | * @see RecyclerView.ViewHolder#getAdapterPosition()
58 | */
59 | void onItemDismiss(int position);
60 | }
61 |
--------------------------------------------------------------------------------
/app/src/main/java/com/agn/v2ray/helper/ItemTouchHelperViewHolder.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2015 Paul Burke
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package com.agn.v2ray.helper;
18 |
19 | import androidx.recyclerview.widget.ItemTouchHelper;
20 |
21 | /**
22 | * Interface to notify an item ViewHolder of relevant callbacks from {@link
23 | * ItemTouchHelper.Callback}.
24 | *
25 | * @author Paul Burke (ipaulpro)
26 | */
27 | public interface ItemTouchHelperViewHolder {
28 |
29 | /**
30 | * Called when the {@link ItemTouchHelper} first registers an item as being moved or swiped.
31 | * Implementations should update the item view to indicate it's active state.
32 | */
33 | void onItemSelected();
34 |
35 |
36 | /**
37 | * Called when the {@link ItemTouchHelper} has completed the move or swipe, and the active item
38 | * state should be cleared.
39 | */
40 | void onItemClear();
41 | }
42 |
--------------------------------------------------------------------------------
/app/src/main/java/com/agn/v2ray/helper/OnStartDragListener.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2015 Paul Burke
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package com.agn.v2ray.helper;
18 |
19 | import androidx.recyclerview.widget.RecyclerView;
20 |
21 | /**
22 | * Listener for manual initiation of a drag.
23 | */
24 | public interface OnStartDragListener {
25 |
26 | /**
27 | * Called when a view is requesting a start of a drag.
28 | *
29 | * @param viewHolder The holder of the view to drag.
30 | */
31 | void onStartDrag(RecyclerView.ViewHolder viewHolder);
32 |
33 | }
34 |
--------------------------------------------------------------------------------
/app/src/main/kotlin/com/agn/v2ray/AngApplication.kt:
--------------------------------------------------------------------------------
1 | package com.agn.v2ray
2 |
3 | import android.content.Context
4 | import androidx.multidex.MultiDexApplication
5 | import androidx.preference.PreferenceManager
6 | import androidx.work.Configuration
7 | import com.agn.v2ray.util.MyContextWrapper
8 | import com.tencent.mmkv.MMKV
9 |
10 | class AngApplication : MultiDexApplication(), Configuration.Provider {
11 | companion object {
12 | const val PREF_LAST_VERSION = "pref_last_version"
13 | lateinit var application: AngApplication
14 | }
15 |
16 | override fun attachBaseContext(newBase: Context) {
17 | val context = MyContextWrapper.wrap(newBase)
18 | application = this
19 | super.attachBaseContext(context)
20 | }
21 |
22 |
23 | var firstRun = false
24 | private set
25 |
26 | override fun onCreate() {
27 | super.onCreate()
28 | ThemeSettings.getInstance(this).refreshTheme();
29 |
30 | val defaultSharedPreferences = PreferenceManager.getDefaultSharedPreferences(this)
31 | firstRun = defaultSharedPreferences.getInt(PREF_LAST_VERSION, 0) != BuildConfig.VERSION_CODE
32 | if (firstRun)
33 | defaultSharedPreferences.edit().putInt(PREF_LAST_VERSION, BuildConfig.VERSION_CODE)
34 | .apply()
35 |
36 | //Logger.init().logLevel(if (BuildConfig.DEBUG) LogLevel.FULL else LogLevel.NONE)
37 | MMKV.initialize(this)
38 |
39 | }
40 |
41 | override fun getWorkManagerConfiguration(): Configuration {
42 | return Configuration.Builder()
43 | .setDefaultProcessName("${BuildConfig.APPLICATION_ID}:bg")
44 | .build()
45 | }
46 | }
47 |
--------------------------------------------------------------------------------
/app/src/main/kotlin/com/agn/v2ray/SplashActivity.kt:
--------------------------------------------------------------------------------
1 | package com.agn.v2ray
2 |
3 | import android.annotation.SuppressLint
4 | import android.content.Intent
5 | import android.content.SharedPreferences
6 | import android.os.Bundle
7 | import android.os.Handler
8 | import android.os.Looper
9 | import android.widget.TextView
10 | import androidx.appcompat.app.AppCompatActivity
11 | import com.agn.v2ray.databinding.ActivitySplashBinding
12 | import com.agn.v2ray.ui.MainActivity
13 |
14 | @SuppressLint("CustomSplashScreen")
15 | class SplashActivity : AppCompatActivity() {
16 | override fun onCreate(savedInstanceState: Bundle?) {
17 | super.onCreate(savedInstanceState)
18 | setContentView(R.layout.activity_splash)
19 | supportActionBar?.hide()
20 | Handler(Looper.getMainLooper()).postDelayed({
21 |
22 | startActivity(Intent(this, MainActivity::class.java))
23 |
24 | finish()
25 | }, 2000)
26 | }
27 | }
--------------------------------------------------------------------------------
/app/src/main/kotlin/com/agn/v2ray/dto/AngConfig.kt:
--------------------------------------------------------------------------------
1 | package com.agn.v2ray.dto
2 |
3 | data class AngConfig(
4 | var index: Int,
5 | var vmess: ArrayList,
6 | var subItem: ArrayList
7 | ) {
8 | data class VmessBean(var guid: String = "123456",
9 | var address: String = "v2ray.cool",
10 | var port: Int = 10086,
11 | var id: String = "a3482e88-686a-4a58-8126-99c9df64b7bf",
12 | var alterId: Int = 64,
13 | var security: String = "aes-128-cfb",
14 | var network: String = "tcp",
15 | var remarks: String = "def",
16 | var headerType: String = "",
17 | var requestHost: String = "",
18 | var path: String = "",
19 | var streamSecurity: String = "",
20 | var allowInsecure: String = "",
21 | var configType: Int = 1,
22 | var configVersion: Int = 1,
23 | var testResult: String = "",
24 | var subid: String = "",
25 | var flow: String = "",
26 | var sni: String = "")
27 |
28 | data class SubItemBean(var id: String = "",
29 | var remarks: String = "",
30 | var url: String = "",
31 | var enabled: Boolean = true)
32 | }
33 |
--------------------------------------------------------------------------------
/app/src/main/kotlin/com/agn/v2ray/dto/AppInfo.kt:
--------------------------------------------------------------------------------
1 | package com.agn.v2ray.dto
2 |
3 | import android.graphics.drawable.Drawable
4 |
5 | data class AppInfo(val appName: String,
6 | val packageName: String,
7 | val appIcon: Drawable,
8 | val isSystemApp: Boolean,
9 | var isSelected: Int)
--------------------------------------------------------------------------------
/app/src/main/kotlin/com/agn/v2ray/dto/EConfigType.kt:
--------------------------------------------------------------------------------
1 | package com.agn.v2ray.dto
2 |
3 | enum class EConfigType(val value: Int, val protocolScheme: String) {
4 | VMESS(1, "vmess://"),
5 | CUSTOM(2, ""),
6 | SHADOWSOCKS(3, "ss://"),
7 | SOCKS(4, "socks://"),
8 | VLESS(5, "vless://"),
9 | TROJAN(6, "trojan://"),
10 | WIREGUARD(7, "wireguard://");
11 |
12 | companion object {
13 | fun fromInt(value: Int) = values().firstOrNull { it.value == value }
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/app/src/main/kotlin/com/agn/v2ray/dto/ERoutingMode.kt:
--------------------------------------------------------------------------------
1 | package com.agn.v2ray.dto
2 |
3 | enum class ERoutingMode(val value: String ) {
4 | GLOBAL_PROXY("0"),
5 | BYPASS_LAN("1"),
6 | BYPASS_MAINLAND("2"),
7 | BYPASS_LAN_MAINLAND("3"),
8 | GLOBAL_DIRECT("4");
9 | }
10 |
--------------------------------------------------------------------------------
/app/src/main/kotlin/com/agn/v2ray/dto/ServerAffiliationInfo.kt:
--------------------------------------------------------------------------------
1 | package com.agn.v2ray.dto
2 |
3 | data class ServerAffiliationInfo(var testDelayMillis: Long = 0L) {
4 | fun getTestDelayString(): String {
5 | if (testDelayMillis == 0L) {
6 | return ""
7 | }
8 | return testDelayMillis.toString() + "ms"
9 | }
10 | }
11 |
--------------------------------------------------------------------------------
/app/src/main/kotlin/com/agn/v2ray/dto/ServerConfig.kt:
--------------------------------------------------------------------------------
1 | package com.agn.v2ray.dto
2 |
3 | import com.agn.v2ray.AppConfig.TAG_AGENT
4 | import com.agn.v2ray.AppConfig.TAG_BLOCKED
5 | import com.agn.v2ray.AppConfig.TAG_DIRECT
6 | import com.agn.v2ray.util.Utils
7 |
8 | data class ServerConfig(
9 | val configVersion: Int = 3,
10 | val configType: EConfigType,
11 | var subscriptionId: String = "",
12 | val addedTime: Long = System.currentTimeMillis(),
13 | var remarks: String = "",
14 | val outboundBean: V2rayConfig.OutboundBean? = null,
15 | var fullConfig: V2rayConfig? = null
16 | ) {
17 | companion object {
18 | fun create(configType: EConfigType): ServerConfig {
19 | when(configType) {
20 | EConfigType.VMESS, EConfigType.VLESS ->
21 | return ServerConfig(
22 | configType = configType,
23 | outboundBean = V2rayConfig.OutboundBean(
24 | protocol = configType.name.lowercase(),
25 | settings = V2rayConfig.OutboundBean.OutSettingsBean(
26 | vnext = listOf(V2rayConfig.OutboundBean.OutSettingsBean.VnextBean(
27 | users = listOf(V2rayConfig.OutboundBean.OutSettingsBean.VnextBean.UsersBean())))),
28 | streamSettings = V2rayConfig.OutboundBean.StreamSettingsBean()))
29 | EConfigType.CUSTOM, EConfigType.WIREGUARD ->
30 | return ServerConfig(configType = configType)
31 | EConfigType.SHADOWSOCKS, EConfigType.SOCKS, EConfigType.TROJAN ->
32 | return ServerConfig(
33 | configType = configType,
34 | outboundBean = V2rayConfig.OutboundBean(
35 | protocol = configType.name.lowercase(),
36 | settings = V2rayConfig.OutboundBean.OutSettingsBean(
37 | servers = listOf(V2rayConfig.OutboundBean.OutSettingsBean.ServersBean())),
38 | streamSettings = V2rayConfig.OutboundBean.StreamSettingsBean()))
39 | }
40 | }
41 | }
42 |
43 | fun getProxyOutbound(): V2rayConfig.OutboundBean? {
44 | if (configType != EConfigType.CUSTOM) {
45 | return outboundBean
46 | }
47 | return fullConfig?.getProxyOutbound()
48 | }
49 |
50 | fun getAllOutboundTags(): MutableList {
51 | if (configType != EConfigType.CUSTOM) {
52 | return mutableListOf(TAG_AGENT, TAG_DIRECT, TAG_BLOCKED)
53 | }
54 | fullConfig?.let { config ->
55 | return config.outbounds.map { it.tag }.toMutableList()
56 | }
57 | return mutableListOf()
58 | }
59 |
60 | fun getV2rayPointDomainAndPort(): String {
61 | val address = getProxyOutbound()?.getServerAddress().orEmpty()
62 | val port = getProxyOutbound()?.getServerPort()
63 | return if (Utils.isIpv6Address(address)) {
64 | String.format("[%s]:%s", address, port)
65 | } else {
66 | String.format("%s:%s", address, port)
67 | }
68 | }
69 | }
70 |
--------------------------------------------------------------------------------
/app/src/main/kotlin/com/agn/v2ray/dto/ServersCache.kt:
--------------------------------------------------------------------------------
1 | package com.agn.v2ray.dto
2 |
3 | data class ServersCache(val guid: String,
4 | val config: ServerConfig)
--------------------------------------------------------------------------------
/app/src/main/kotlin/com/agn/v2ray/dto/SubscriptionItem.kt:
--------------------------------------------------------------------------------
1 | package com.agn.v2ray.dto
2 |
3 | data class SubscriptionItem(
4 | var remarks: String = "",
5 | var url: String = "",
6 | var enabled: Boolean = true,
7 | val addedTime: Long = System.currentTimeMillis(),
8 | var lastUpdated: Long = -1,
9 | var autoUpdate: Boolean = false,
10 | val updateInterval: Int? = null,
11 | )
--------------------------------------------------------------------------------
/app/src/main/kotlin/com/agn/v2ray/dto/VmessQRCode.kt:
--------------------------------------------------------------------------------
1 | package com.agn.v2ray.dto
2 |
3 | data class VmessQRCode(var v: String = "",
4 | var ps: String = "",
5 | var add: String = "",
6 | var port: String = "",
7 | var id: String = "",
8 | var aid: String = "0",
9 | var scy: String = "",
10 | var net: String = "",
11 | var type: String = "",
12 | var host: String = "",
13 | var path: String = "",
14 | var tls: String = "",
15 | var sni: String = "",
16 | var alpn: String = "",
17 | var fp: String = "")
--------------------------------------------------------------------------------
/app/src/main/kotlin/com/agn/v2ray/extension/_Ext.kt:
--------------------------------------------------------------------------------
1 | package com.agn.v2ray.extension
2 |
3 | import android.content.Context
4 | import android.os.Build
5 | import android.widget.Toast
6 | import com.agn.v2ray.AngApplication
7 | import me.drakeet.support.toast.ToastCompat
8 | import org.json.JSONObject
9 | import java.net.URI
10 | import java.net.URLConnection
11 |
12 | /**
13 | * Some extensions
14 | */
15 |
16 | val Context.v2RayApplication: AngApplication
17 | get() = applicationContext as AngApplication
18 |
19 | fun Context.toast(message: Int): Toast = ToastCompat
20 | .makeText(this, message, Toast.LENGTH_SHORT)
21 | .apply {
22 | show()
23 | }
24 |
25 | fun Context.toast(message: CharSequence): Toast = ToastCompat
26 | .makeText(this, message, Toast.LENGTH_SHORT)
27 | .apply {
28 | show()
29 | }
30 |
31 | fun JSONObject.putOpt(pair: Pair) = putOpt(pair.first, pair.second)
32 | fun JSONObject.putOpt(pairs: Map) = pairs.forEach { putOpt(it.key to it.value) }
33 |
34 | const val threshold = 1000
35 | const val divisor = 1024F
36 |
37 | fun Long.toSpeedString() = toTrafficString() + "/s"
38 |
39 | fun Long.toTrafficString(): String {
40 | if (this == 0L)
41 | return "\t\t\t0\t B"
42 |
43 | if (this < threshold)
44 | return "${this.toFloat().toShortString()}\t B"
45 |
46 | val kib = this / divisor
47 | if (kib < threshold)
48 | return "${kib.toShortString()}\t KB"
49 |
50 | val mib = kib / divisor
51 | if (mib < threshold)
52 | return "${mib.toShortString()}\t MB"
53 |
54 | val gib = mib / divisor
55 | if (gib < threshold)
56 | return "${gib.toShortString()}\t GB"
57 |
58 | val tib = gib / divisor
59 | if (tib < threshold)
60 | return "${tib.toShortString()}\t TB"
61 |
62 | val pib = tib / divisor
63 | if (pib < threshold)
64 | return "${pib.toShortString()}\t PB"
65 |
66 | return "∞"
67 | }
68 |
69 | private fun Float.toShortString(): String {
70 | val s = "%.2f".format(this)
71 | if (s.length <= 4)
72 | return s
73 | return s.substring(0, 4).removeSuffix(".")
74 | }
75 |
76 | val URLConnection.responseLength: Long
77 | get() = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) contentLengthLong else contentLength.toLong()
78 |
79 | val URI.idnHost: String
80 | get() = (host!!).replace("[", "").replace("]", "")
--------------------------------------------------------------------------------
/app/src/main/kotlin/com/agn/v2ray/receiver/TaskerReceiver.kt:
--------------------------------------------------------------------------------
1 | package com.agn.v2ray.receiver
2 |
3 | import android.content.BroadcastReceiver
4 | import android.content.Context
5 | import android.content.Intent
6 | import android.text.TextUtils
7 | import com.google.zxing.WriterException
8 | import com.tencent.mmkv.MMKV
9 | import com.agn.v2ray.AppConfig
10 | import com.agn.v2ray.service.V2RayServiceManager
11 | import com.agn.v2ray.util.MmkvManager
12 |
13 | import com.agn.v2ray.util.Utils
14 |
15 | class TaskerReceiver : BroadcastReceiver() {
16 | private val mainStorage by lazy { MMKV.mmkvWithID(MmkvManager.ID_MAIN, MMKV.MULTI_PROCESS_MODE) }
17 |
18 | override fun onReceive(context: Context, intent: Intent?) {
19 |
20 | try {
21 | val bundle = intent?.getBundleExtra(AppConfig.TASKER_EXTRA_BUNDLE)
22 | val switch = bundle?.getBoolean(AppConfig.TASKER_EXTRA_BUNDLE_SWITCH, false)
23 | val guid = bundle?.getString(AppConfig.TASKER_EXTRA_BUNDLE_GUID, "")
24 |
25 | if (switch == null || guid == null || TextUtils.isEmpty(guid)) {
26 | return
27 | } else if (switch) {
28 | if (guid == AppConfig.TASKER_DEFAULT_GUID) {
29 | Utils.startVServiceFromToggle(context)
30 | } else {
31 | mainStorage?.encode(MmkvManager.KEY_SELECTED_SERVER, guid)
32 | V2RayServiceManager.startV2Ray(context)
33 | }
34 | } else {
35 | Utils.stopVService(context)
36 | }
37 | } catch (e: Exception) {
38 | e.printStackTrace()
39 | }
40 | }
41 | }
42 |
--------------------------------------------------------------------------------
/app/src/main/kotlin/com/agn/v2ray/receiver/WidgetProvider.kt:
--------------------------------------------------------------------------------
1 | package com.agn.v2ray.receiver
2 |
3 | import android.app.PendingIntent
4 | import android.appwidget.AppWidgetManager
5 | import android.appwidget.AppWidgetProvider
6 | import android.content.ComponentName
7 | import android.content.Context
8 | import android.content.Intent
9 | import android.os.Build
10 | import android.widget.RemoteViews
11 | import com.agn.v2ray.R
12 | import com.agn.v2ray.AppConfig
13 | import com.agn.v2ray.service.V2RayServiceManager
14 | import com.agn.v2ray.util.Utils
15 |
16 | class WidgetProvider : AppWidgetProvider() {
17 | /**
18 | * 每次窗口小部件被更新都调用一次该方法
19 | */
20 | override fun onUpdate(context: Context, appWidgetManager: AppWidgetManager, appWidgetIds: IntArray) {
21 | super.onUpdate(context, appWidgetManager, appWidgetIds)
22 | updateWidgetBackground(context, appWidgetManager, appWidgetIds, V2RayServiceManager.v2rayPoint.isRunning)
23 | }
24 |
25 |
26 | private fun updateWidgetBackground(context: Context, appWidgetManager: AppWidgetManager, appWidgetIds: IntArray, isRunning: Boolean) {
27 | val remoteViews = RemoteViews(context.packageName, R.layout.widget_switch)
28 | val intent = Intent(context, WidgetProvider::class.java)
29 | intent.action = AppConfig.BROADCAST_ACTION_WIDGET_CLICK
30 | val pendingIntent = PendingIntent.getBroadcast(
31 | context,
32 | R.id.layout_switch,
33 | intent,
34 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
35 | PendingIntent.FLAG_IMMUTABLE or PendingIntent.FLAG_UPDATE_CURRENT
36 | } else {
37 | PendingIntent.FLAG_UPDATE_CURRENT
38 | })
39 | remoteViews.setOnClickPendingIntent(R.id.layout_switch, pendingIntent)
40 | if (isRunning) {
41 | remoteViews.setInt(
42 | R.id.layout_switch,
43 | "setBackgroundResource",
44 | R.drawable.ic_rounded_corner_theme
45 | )
46 | } else {
47 | remoteViews.setInt(
48 | R.id.layout_switch,
49 | "setBackgroundResource",
50 | R.drawable.ic_rounded_corner_grey
51 | )
52 | }
53 |
54 | for (appWidgetId in appWidgetIds) {
55 | appWidgetManager.updateAppWidget(appWidgetId, remoteViews)
56 | }
57 | }
58 |
59 | /**
60 | * 接收窗口小部件发送的广播
61 | */
62 | override fun onReceive(context: Context, intent: Intent) {
63 | super.onReceive(context, intent)
64 | if (AppConfig.BROADCAST_ACTION_WIDGET_CLICK == intent.action) {
65 | if (V2RayServiceManager.v2rayPoint.isRunning) {
66 | Utils.stopVService(context)
67 | } else {
68 | Utils.startVServiceFromToggle(context)
69 | }
70 | } else if (AppConfig.BROADCAST_ACTION_ACTIVITY == intent.action) {
71 | AppWidgetManager.getInstance(context)?.let { manager ->
72 | when (intent.getIntExtra("key", 0)) {
73 | AppConfig.MSG_STATE_RUNNING, AppConfig.MSG_STATE_START_SUCCESS -> {
74 | updateWidgetBackground(context, manager, manager.getAppWidgetIds(ComponentName(context, WidgetProvider::class.java)),
75 | true)
76 | }
77 | AppConfig.MSG_STATE_NOT_RUNNING, AppConfig.MSG_STATE_START_FAILURE, AppConfig.MSG_STATE_STOP_SUCCESS -> {
78 | updateWidgetBackground(context, manager, manager.getAppWidgetIds(ComponentName(context, WidgetProvider::class.java)),
79 | false)
80 | }
81 | }
82 | }
83 | }
84 | }
85 | }
86 |
--------------------------------------------------------------------------------
/app/src/main/kotlin/com/agn/v2ray/service/QSTileService.kt:
--------------------------------------------------------------------------------
1 | package com.agn.v2ray.service
2 |
3 | import android.annotation.TargetApi
4 | import android.content.BroadcastReceiver
5 | import android.content.Context
6 | import android.content.Intent
7 | import android.content.IntentFilter
8 | import android.graphics.drawable.Icon
9 | import android.os.Build
10 | import android.service.quicksettings.Tile
11 | import android.service.quicksettings.TileService
12 | import com.agn.v2ray.AppConfig
13 | import com.agn.v2ray.R
14 | import com.agn.v2ray.util.MessageUtil
15 | import com.agn.v2ray.util.Utils
16 | import java.lang.ref.SoftReference
17 |
18 | @TargetApi(Build.VERSION_CODES.N)
19 | class QSTileService : TileService() {
20 |
21 | fun setState(state: Int) {
22 | if (state == Tile.STATE_INACTIVE) {
23 | qsTile?.state = Tile.STATE_INACTIVE
24 | qsTile?.label = getString(R.string.app_name)
25 | qsTile?.icon = Icon.createWithResource(applicationContext, R.drawable.ic_v)
26 | } else if (state == Tile.STATE_ACTIVE) {
27 | qsTile?.state = Tile.STATE_ACTIVE
28 | qsTile?.label = V2RayServiceManager.currentConfig?.remarks
29 | qsTile?.icon = Icon.createWithResource(applicationContext, R.drawable.ic_v)
30 | }
31 |
32 | qsTile?.updateTile()
33 | }
34 |
35 | override fun onStartListening() {
36 | super.onStartListening()
37 | setState(Tile.STATE_INACTIVE)
38 | mMsgReceive = ReceiveMessageHandler(this)
39 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
40 | registerReceiver(mMsgReceive, IntentFilter(AppConfig.BROADCAST_ACTION_ACTIVITY), Context.RECEIVER_EXPORTED)
41 | } else {
42 | registerReceiver(mMsgReceive, IntentFilter(AppConfig.BROADCAST_ACTION_ACTIVITY))
43 | }
44 |
45 | MessageUtil.sendMsg2Service(this, AppConfig.MSG_REGISTER_CLIENT, "")
46 | }
47 |
48 | override fun onStopListening() {
49 | super.onStopListening()
50 |
51 | unregisterReceiver(mMsgReceive)
52 | mMsgReceive = null
53 | }
54 |
55 | override fun onClick() {
56 | super.onClick()
57 | when (qsTile.state) {
58 | Tile.STATE_INACTIVE -> {
59 | Utils.startVServiceFromToggle(this)
60 | }
61 | Tile.STATE_ACTIVE -> {
62 | Utils.stopVService(this)
63 | }
64 | }
65 | }
66 |
67 | private var mMsgReceive: BroadcastReceiver? = null
68 |
69 | private class ReceiveMessageHandler(context: QSTileService) : BroadcastReceiver() {
70 | internal var mReference: SoftReference = SoftReference(context)
71 | override fun onReceive(ctx: Context?, intent: Intent?) {
72 | val context = mReference.get()
73 | when (intent?.getIntExtra("key", 0)) {
74 | AppConfig.MSG_STATE_RUNNING -> {
75 | context?.setState(Tile.STATE_ACTIVE)
76 | }
77 | AppConfig.MSG_STATE_NOT_RUNNING -> {
78 | context?.setState(Tile.STATE_INACTIVE)
79 | }
80 | AppConfig.MSG_STATE_START_SUCCESS -> {
81 | context?.setState(Tile.STATE_ACTIVE)
82 | }
83 | AppConfig.MSG_STATE_START_FAILURE -> {
84 | context?.setState(Tile.STATE_INACTIVE)
85 | }
86 | AppConfig.MSG_STATE_STOP_SUCCESS -> {
87 | context?.setState(Tile.STATE_INACTIVE)
88 | }
89 | }
90 | }
91 | }
92 | }
93 |
--------------------------------------------------------------------------------
/app/src/main/kotlin/com/agn/v2ray/service/ServiceControl.kt:
--------------------------------------------------------------------------------
1 | package com.agn.v2ray.service
2 |
3 | import android.app.Service
4 |
5 | interface ServiceControl {
6 | fun getService(): Service
7 |
8 | fun startService()
9 |
10 | fun stopService()
11 |
12 | fun vpnProtect(socket: Int): Boolean
13 | }
14 |
--------------------------------------------------------------------------------
/app/src/main/kotlin/com/agn/v2ray/service/SubscriptionUpdater.kt:
--------------------------------------------------------------------------------
1 | package com.agn.v2ray.service
2 |
3 | import android.annotation.SuppressLint
4 | import android.app.NotificationChannel
5 | import android.app.NotificationManager
6 | import android.content.Context
7 | import android.os.Build
8 | import android.util.Log
9 | import androidx.core.app.NotificationCompat
10 | import androidx.core.app.NotificationManagerCompat
11 | import androidx.work.CoroutineWorker
12 | import androidx.work.WorkerParameters
13 | import com.agn.v2ray.AppConfig
14 | import com.agn.v2ray.R
15 | import com.agn.v2ray.util.AngConfigManager
16 | import com.agn.v2ray.util.MmkvManager
17 | import com.agn.v2ray.util.Utils
18 |
19 | object SubscriptionUpdater {
20 |
21 | const val notificationChannel = "subscription_update_channel"
22 |
23 | class UpdateTask(context: Context, params: WorkerParameters) :
24 | CoroutineWorker(context, params) {
25 |
26 | private val notificationManager = NotificationManagerCompat.from(applicationContext)
27 | private val notification =
28 | NotificationCompat.Builder(applicationContext, notificationChannel)
29 | .setWhen(0)
30 | .setTicker("Update")
31 | .setContentTitle(context.getString(R.string.title_pref_auto_update_subscription))
32 | .setSmallIcon(R.drawable.ic_v)
33 | .setCategory(NotificationCompat.CATEGORY_SERVICE)
34 | .setPriority(NotificationCompat.PRIORITY_DEFAULT)
35 |
36 | @SuppressLint("MissingPermission")
37 | override suspend fun doWork(): Result {
38 | Log.d(AppConfig.ANG_PACKAGE, "subscription automatic update starting")
39 |
40 | val subs = MmkvManager.decodeSubscriptions().filter { it.second.autoUpdate }
41 |
42 | for (i in subs) {
43 | val subscription = i.second
44 |
45 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
46 | notification.setChannelId(notificationChannel)
47 | val channel =
48 | NotificationChannel(
49 | notificationChannel,
50 | "Subscription Update Service",
51 | NotificationManager.IMPORTANCE_MIN
52 | )
53 | notificationManager.createNotificationChannel(channel)
54 | }
55 | notificationManager.notify(3, notification.build())
56 | Log.d(
57 | AppConfig.ANG_PACKAGE,
58 | "subscription automatic update: ---${subscription.remarks}"
59 | )
60 | val configs = Utils.getUrlContentWithCustomUserAgent(subscription.url)
61 | importBatchConfig(configs, i.first)
62 | notification.setContentText("Updating ${subscription.remarks}")
63 | }
64 | notificationManager.cancel(3)
65 | return Result.success()
66 | }
67 | }
68 |
69 | fun importBatchConfig(server: String?, subid: String = "") {
70 | val append = subid.isEmpty()
71 |
72 | val count = AngConfigManager.importBatchConfig(server, subid, append)
73 | if (count <= 0) {
74 | AngConfigManager.importBatchConfig(Utils.decode(server!!), subid, append)
75 | }
76 | }
77 | }
--------------------------------------------------------------------------------
/app/src/main/kotlin/com/agn/v2ray/service/V2RayProxyOnlyService.kt:
--------------------------------------------------------------------------------
1 | package com.agn.v2ray.service
2 |
3 | import android.app.Service
4 | import android.content.Context
5 | import android.content.Intent
6 | import android.os.Build
7 | import android.os.IBinder
8 | import androidx.annotation.RequiresApi
9 | import com.agn.v2ray.util.MyContextWrapper
10 | import com.agn.v2ray.util.Utils
11 | import java.lang.ref.SoftReference
12 |
13 | class V2RayProxyOnlyService : Service(), ServiceControl {
14 | override fun onCreate() {
15 | super.onCreate()
16 | V2RayServiceManager.serviceControl = SoftReference(this)
17 | }
18 |
19 | override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
20 | V2RayServiceManager.startV2rayPoint()
21 | return START_STICKY
22 | }
23 |
24 | override fun onDestroy() {
25 | super.onDestroy()
26 | V2RayServiceManager.stopV2rayPoint()
27 | }
28 |
29 | override fun getService(): Service {
30 | return this
31 | }
32 |
33 | override fun startService() {
34 | // do nothing
35 | }
36 |
37 | override fun stopService() {
38 | stopSelf()
39 | }
40 |
41 | override fun vpnProtect(socket: Int): Boolean {
42 | return true
43 | }
44 |
45 | override fun onBind(intent: Intent?): IBinder? {
46 | return null
47 | }
48 |
49 | @RequiresApi(Build.VERSION_CODES.N)
50 | override fun attachBaseContext(newBase: Context) {
51 | val context = MyContextWrapper.wrap(newBase)
52 | super.attachBaseContext(context)
53 | }
54 | }
55 |
--------------------------------------------------------------------------------
/app/src/main/kotlin/com/agn/v2ray/service/V2RayTestService.kt:
--------------------------------------------------------------------------------
1 | package com.agn.v2ray.service
2 |
3 | import android.app.Service
4 | import android.content.Intent
5 | import android.os.IBinder
6 | import com.agn.v2ray.AppConfig.MSG_MEASURE_CONFIG
7 | import com.agn.v2ray.AppConfig.MSG_MEASURE_CONFIG_CANCEL
8 | import com.agn.v2ray.AppConfig.MSG_MEASURE_CONFIG_SUCCESS
9 | import com.agn.v2ray.util.MessageUtil
10 | import com.agn.v2ray.util.SpeedtestUtil
11 | import com.agn.v2ray.util.Utils
12 | import go.Seq
13 | import kotlinx.coroutines.*
14 | import libv2ray.Libv2ray
15 | import java.util.concurrent.Executors
16 |
17 | class V2RayTestService : Service() {
18 | private val realTestScope by lazy { CoroutineScope(Executors.newFixedThreadPool(10).asCoroutineDispatcher()) }
19 |
20 | override fun onCreate() {
21 | super.onCreate()
22 | Seq.setContext(this)
23 | Libv2ray.initV2Env(Utils.userAssetPath(this), Utils.getDeviceIdForXUDPBaseKey())
24 | }
25 |
26 | override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
27 | when (intent?.getIntExtra("key", 0)) {
28 | MSG_MEASURE_CONFIG -> {
29 | val contentPair = intent.getSerializableExtra("content") as Pair
30 | realTestScope.launch {
31 | val result = SpeedtestUtil.realPing(contentPair.second)
32 | MessageUtil.sendMsg2UI(this@V2RayTestService, MSG_MEASURE_CONFIG_SUCCESS, Pair(contentPair.first, result))
33 | }
34 | }
35 | MSG_MEASURE_CONFIG_CANCEL -> {
36 | realTestScope.coroutineContext[Job]?.cancelChildren()
37 | }
38 | }
39 | return super.onStartCommand(intent, flags, startId)
40 | }
41 |
42 | override fun onBind(intent: Intent?): IBinder? {
43 | return null
44 | }
45 | }
46 |
--------------------------------------------------------------------------------
/app/src/main/kotlin/com/agn/v2ray/ui/AboutActivity.kt:
--------------------------------------------------------------------------------
1 | package com.agn.v2ray.ui
2 |
3 | import com.agn.v2ray.R
4 | import android.annotation.SuppressLint
5 | import android.app.AlertDialog
6 | import android.content.Intent
7 | import android.net.Uri
8 | import android.os.Bundle
9 | import android.text.Html
10 | import android.view.View
11 | import androidx.appcompat.app.AppCompatActivity
12 |
13 |
14 | class AboutActivity : AppCompatActivity() {
15 |
16 |
17 | override fun onCreate(savedInstanceState: Bundle?) {
18 | super.onCreate(savedInstanceState)
19 | setContentView(R.layout.activity_about)
20 | title = getString(R.string.about)
21 |
22 | }
23 |
24 |
25 | }
--------------------------------------------------------------------------------
/app/src/main/kotlin/com/agn/v2ray/ui/BaseActivity.kt:
--------------------------------------------------------------------------------
1 | package com.agn.v2ray.ui
2 |
3 | import android.content.Context
4 | import android.os.Build
5 | import android.os.Bundle
6 | import android.view.MenuItem
7 | import androidx.annotation.RequiresApi
8 | import androidx.appcompat.app.AppCompatActivity
9 | import androidx.core.view.WindowCompat
10 | import com.agn.v2ray.util.MyContextWrapper
11 | import com.agn.v2ray.util.Utils
12 |
13 | abstract class BaseActivity : AppCompatActivity() {
14 | override fun onCreate(savedInstanceState: Bundle?) {
15 | super.onCreate(savedInstanceState)
16 |
17 | if (!Utils.getDarkModeStatus(this)) {
18 | WindowCompat.getInsetsController(window, window.decorView).apply {
19 | isAppearanceLightStatusBars = true
20 | }
21 | }
22 | }
23 | override fun onOptionsItemSelected(item: MenuItem) = when (item.itemId) {
24 | android.R.id.home -> {
25 | onBackPressed()
26 | true
27 | }
28 | else -> super.onOptionsItemSelected(item)
29 | }
30 |
31 | @RequiresApi(Build.VERSION_CODES.N)
32 | override fun attachBaseContext(newBase: Context) {
33 | val context = MyContextWrapper.wrap(newBase)
34 | super.attachBaseContext(context)
35 | }
36 | }
37 |
--------------------------------------------------------------------------------
/app/src/main/kotlin/com/agn/v2ray/ui/FragmentAdapter.kt:
--------------------------------------------------------------------------------
1 | package com.agn.v2ray.ui
2 |
3 | import androidx.fragment.app.Fragment
4 | import androidx.fragment.app.FragmentActivity
5 | import androidx.viewpager2.adapter.FragmentStateAdapter
6 |
7 | class FragmentAdapter(fragmentActivity: FragmentActivity, private val mFragments: List) :
8 | FragmentStateAdapter(fragmentActivity) {
9 |
10 | override fun createFragment(position: Int): Fragment {
11 | return mFragments[position]
12 | }
13 |
14 | override fun getItemCount(): Int {
15 | return mFragments.size
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/app/src/main/kotlin/com/agn/v2ray/ui/LogcatActivity.kt:
--------------------------------------------------------------------------------
1 | package com.agn.v2ray.ui
2 |
3 | import android.os.Handler
4 | import android.os.Looper
5 | import android.os.Bundle
6 | import android.text.method.ScrollingMovementMethod
7 | import android.view.Menu
8 | import android.view.MenuItem
9 | import android.view.View
10 | import androidx.lifecycle.lifecycleScope
11 | import com.agn.v2ray.AppConfig.ANG_PACKAGE
12 | import com.agn.v2ray.R
13 | import com.agn.v2ray.databinding.ActivityLogcatBinding
14 | import com.agn.v2ray.extension.toast
15 | import com.agn.v2ray.util.Utils
16 | import kotlinx.coroutines.Dispatchers
17 | import kotlinx.coroutines.GlobalScope
18 | import kotlinx.coroutines.launch
19 |
20 | import java.io.IOException
21 | import java.util.LinkedHashSet
22 |
23 | class LogcatActivity : BaseActivity() {
24 | private lateinit var binding: ActivityLogcatBinding
25 |
26 | override fun onCreate(savedInstanceState: Bundle?) {
27 | super.onCreate(savedInstanceState)
28 | binding = ActivityLogcatBinding.inflate(layoutInflater)
29 | val view = binding.root
30 | setContentView(view)
31 |
32 | title = getString(R.string.title_logcat)
33 |
34 | logcat(false)
35 | }
36 |
37 | private fun logcat(shouldFlushLog: Boolean) {
38 |
39 | try {
40 | binding.pbWaiting.visibility = View.VISIBLE
41 |
42 | lifecycleScope.launch(Dispatchers.Default) {
43 | if (shouldFlushLog) {
44 | val lst = LinkedHashSet()
45 | lst.add("logcat")
46 | lst.add("-c")
47 | val process = Runtime.getRuntime().exec(lst.toTypedArray())
48 | process.waitFor()
49 | }
50 | val lst = LinkedHashSet()
51 | lst.add("logcat")
52 | lst.add("-d")
53 | lst.add("-v")
54 | lst.add("time")
55 | lst.add("-s")
56 | lst.add("GoLog,tun2socks,${ANG_PACKAGE},AndroidRuntime,System.err")
57 | val process = Runtime.getRuntime().exec(lst.toTypedArray())
58 | // val bufferedReader = BufferedReader(
59 | // InputStreamReader(process.inputStream))
60 | // val allText = bufferedReader.use(BufferedReader::readText)
61 | val allText = process.inputStream.bufferedReader().use { it.readText() }
62 | launch(Dispatchers.Main) {
63 | binding.tvLogcat.text = allText
64 | binding.tvLogcat.movementMethod = ScrollingMovementMethod()
65 | binding.pbWaiting.visibility = View.GONE
66 | Handler(Looper.getMainLooper()).post { binding.svLogcat.fullScroll(View.FOCUS_DOWN) }
67 | }
68 | }
69 | } catch (e: IOException) {
70 | e.printStackTrace()
71 | }
72 | }
73 |
74 | override fun onCreateOptionsMenu(menu: Menu): Boolean {
75 | menuInflater.inflate(R.menu.menu_logcat, menu)
76 | return super.onCreateOptionsMenu(menu)
77 | }
78 |
79 | override fun onOptionsItemSelected(item: MenuItem) = when (item.itemId) {
80 | R.id.copy_all -> {
81 | Utils.setClipboard(this, binding.tvLogcat.text.toString())
82 | toast(R.string.toast_success)
83 | true
84 | }
85 | R.id.clear_all -> {
86 | logcat(true)
87 | true
88 | }
89 | else -> super.onOptionsItemSelected(item)
90 | }
91 | }
92 |
--------------------------------------------------------------------------------
/app/src/main/kotlin/com/agn/v2ray/ui/PerAppProxyAdapter.kt:
--------------------------------------------------------------------------------
1 | package com.agn.v2ray.ui
2 |
3 | import android.view.LayoutInflater
4 | import androidx.recyclerview.widget.RecyclerView
5 | import android.view.View
6 | import android.view.ViewGroup
7 | import com.agn.v2ray.R
8 | import com.agn.v2ray.databinding.ItemRecyclerBypassListBinding
9 | import com.agn.v2ray.dto.AppInfo
10 | import java.util.*
11 |
12 | class PerAppProxyAdapter(val activity: BaseActivity, val apps: List, blacklist: MutableSet?) :
13 | RecyclerView.Adapter() {
14 |
15 | companion object {
16 | private const val VIEW_TYPE_HEADER = 0
17 | private const val VIEW_TYPE_ITEM = 1
18 | }
19 |
20 | val blacklist = if (blacklist == null) HashSet() else HashSet(blacklist)
21 |
22 | override fun onBindViewHolder(holder: BaseViewHolder, position: Int) {
23 | if (holder is AppViewHolder) {
24 | val appInfo = apps[position - 1]
25 | holder.bind(appInfo)
26 | }
27 | }
28 |
29 | override fun getItemCount() = apps.size + 1
30 |
31 | override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): BaseViewHolder {
32 | val ctx = parent.context
33 |
34 | return when (viewType) {
35 | VIEW_TYPE_HEADER -> {
36 | val view = View(ctx)
37 | view.layoutParams = ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,
38 | ctx.resources.getDimensionPixelSize(R.dimen.bypass_list_header_height) * 0)
39 | BaseViewHolder(view)
40 | }
41 | // VIEW_TYPE_ITEM -> AppViewHolder(ctx.layoutInflater
42 | // .inflate(R.layout.item_recycler_bypass_list, parent, false))
43 |
44 | else -> AppViewHolder(ItemRecyclerBypassListBinding.inflate(LayoutInflater.from(ctx), parent, false))
45 |
46 | }
47 | }
48 |
49 | override fun getItemViewType(position: Int) = if (position == 0) VIEW_TYPE_HEADER else VIEW_TYPE_ITEM
50 |
51 | open class BaseViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView)
52 |
53 | inner class AppViewHolder(private val itemBypassBinding: ItemRecyclerBypassListBinding) : BaseViewHolder(itemBypassBinding.root),
54 | View.OnClickListener {
55 | private val inBlacklist: Boolean get() = blacklist.contains(appInfo.packageName)
56 | private lateinit var appInfo: AppInfo
57 |
58 | fun bind(appInfo: AppInfo) {
59 | this.appInfo = appInfo
60 |
61 | itemBypassBinding.icon.setImageDrawable(appInfo.appIcon)
62 | // name.text = appInfo.appName
63 |
64 | itemBypassBinding.checkBox.isChecked = inBlacklist
65 | itemBypassBinding.packageName.text = appInfo.packageName
66 | if (appInfo.isSystemApp) {
67 | itemBypassBinding.name.text = String.format("** %1s", appInfo.appName)
68 | //name.textColor = Color.RED
69 | } else {
70 | itemBypassBinding.name.text = appInfo.appName
71 | //name.textColor = Color.DKGRAY
72 | }
73 |
74 | itemView.setOnClickListener(this)
75 | }
76 |
77 | override fun onClick(v: View?) {
78 | if (inBlacklist) {
79 | blacklist.remove(appInfo.packageName)
80 | itemBypassBinding.checkBox.isChecked = false
81 | } else {
82 | blacklist.add(appInfo.packageName)
83 | itemBypassBinding.checkBox.isChecked = true
84 | }
85 | }
86 | }
87 | }
88 |
--------------------------------------------------------------------------------
/app/src/main/kotlin/com/agn/v2ray/ui/RoutingSettingsActivity.kt:
--------------------------------------------------------------------------------
1 | package com.agn.v2ray.ui
2 |
3 | import android.os.Bundle
4 | import com.agn.v2ray.R
5 | import androidx.fragment.app.Fragment
6 | import com.google.android.material.tabs.TabLayoutMediator
7 | import com.agn.v2ray.AppConfig
8 | import com.agn.v2ray.databinding.ActivityRoutingSettingsBinding
9 |
10 | class RoutingSettingsActivity : BaseActivity() {
11 | private lateinit var binding: ActivityRoutingSettingsBinding
12 |
13 | private val titles: Array by lazy {
14 | resources.getStringArray(R.array.routing_tag)
15 | }
16 |
17 | override fun onCreate(savedInstanceState: Bundle?) {
18 | super.onCreate(savedInstanceState)
19 | binding = ActivityRoutingSettingsBinding.inflate(layoutInflater)
20 | val view = binding.root
21 | setContentView(view)
22 |
23 | title = getString(R.string.title_pref_routing_custom)
24 |
25 |
26 | val fragments = ArrayList()
27 | fragments.add(RoutingSettingsFragment().newInstance(AppConfig.PREF_V2RAY_ROUTING_AGENT))
28 | fragments.add(RoutingSettingsFragment().newInstance(AppConfig.PREF_V2RAY_ROUTING_DIRECT))
29 | fragments.add(RoutingSettingsFragment().newInstance(AppConfig.PREF_V2RAY_ROUTING_BLOCKED))
30 |
31 | val adapter = FragmentAdapter(this, fragments)
32 | binding.viewpager.adapter = adapter
33 | //tablayout.setTabTextColors(Color.BLACK, Color.RED)
34 | TabLayoutMediator(binding.tablayout, binding.viewpager) { tab, position ->
35 | tab.text = titles[position]
36 | }.attach()
37 | }
38 | }
39 |
--------------------------------------------------------------------------------
/app/src/main/kotlin/com/agn/v2ray/ui/ScScannerActivity.kt:
--------------------------------------------------------------------------------
1 | package com.agn.v2ray.ui
2 |
3 | import android.Manifest
4 | import android.content.*
5 | import com.tbruyelle.rxpermissions.RxPermissions
6 | import com.agn.v2ray.R
7 | import com.agn.v2ray.util.AngConfigManager
8 | import android.os.Bundle
9 | import androidx.activity.result.contract.ActivityResultContracts
10 | import com.agn.v2ray.extension.toast
11 |
12 | class ScScannerActivity : BaseActivity() {
13 |
14 | override fun onCreate(savedInstanceState: Bundle?) {
15 | super.onCreate(savedInstanceState)
16 | setContentView(R.layout.activity_none)
17 | importQRcode()
18 | }
19 |
20 | fun importQRcode(): Boolean {
21 | RxPermissions(this)
22 | .request(Manifest.permission.CAMERA)
23 | .subscribe {
24 | if (it)
25 | scanQRCode.launch(Intent(this, ScannerActivity::class.java))
26 | else
27 | toast(R.string.toast_permission_denied)
28 | }
29 |
30 | return true
31 | }
32 |
33 | private val scanQRCode = registerForActivityResult(ActivityResultContracts.StartActivityForResult()) {
34 | if (it.resultCode == RESULT_OK) {
35 | val count = AngConfigManager.importBatchConfig(it.data?.getStringExtra("SCAN_RESULT"), "", false)
36 | if (count > 0) {
37 | toast(R.string.toast_success)
38 | } else {
39 | toast(R.string.toast_failure)
40 | }
41 | startActivity(Intent(this, MainActivity::class.java))
42 | }
43 | finish()
44 | }
45 | }
46 |
--------------------------------------------------------------------------------
/app/src/main/kotlin/com/agn/v2ray/ui/ScSwitchActivity.kt:
--------------------------------------------------------------------------------
1 | package com.agn.v2ray.ui
2 |
3 | import com.agn.v2ray.R
4 | import com.agn.v2ray.util.Utils
5 | import android.os.Bundle
6 | import com.agn.v2ray.service.V2RayServiceManager
7 |
8 | class ScSwitchActivity : BaseActivity() {
9 | override fun onCreate(savedInstanceState: Bundle?) {
10 | super.onCreate(savedInstanceState)
11 | moveTaskToBack(true)
12 |
13 | setContentView(R.layout.activity_none)
14 |
15 | if (V2RayServiceManager.v2rayPoint.isRunning) {
16 | Utils.stopVService(this)
17 | } else {
18 | Utils.startVServiceFromToggle(this)
19 | }
20 | finish()
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/app/src/main/kotlin/com/agn/v2ray/ui/ScannerActivity.kt:
--------------------------------------------------------------------------------
1 | package com.agn.v2ray.ui
2 |
3 | import android.Manifest
4 | import android.app.Activity
5 | import android.os.Bundle
6 | import android.content.Intent
7 | import android.graphics.BitmapFactory
8 | import android.os.Build
9 | import android.view.Menu
10 | import android.view.MenuItem
11 | import androidx.activity.result.contract.ActivityResultContracts
12 | import com.tbruyelle.rxpermissions.RxPermissions
13 | import com.tencent.mmkv.MMKV
14 | import com.agn.v2ray.AppConfig
15 | import com.agn.v2ray.R
16 | import com.agn.v2ray.extension.toast
17 | import com.agn.v2ray.util.MmkvManager
18 | import com.agn.v2ray.util.QRCodeDecoder
19 | import io.github.g00fy2.quickie.QRResult
20 | import io.github.g00fy2.quickie.ScanCustomCode
21 | import io.github.g00fy2.quickie.config.ScannerConfig
22 |
23 | class ScannerActivity : BaseActivity(){
24 |
25 | private val scanQrCode = registerForActivityResult(ScanCustomCode(), ::handleResult)
26 | private val settingsStorage by lazy { MMKV.mmkvWithID(MmkvManager.ID_SETTING, MMKV.MULTI_PROCESS_MODE) }
27 |
28 | public override fun onCreate(savedInstanceState: Bundle?) {
29 | super.onCreate(savedInstanceState)
30 |
31 | if (settingsStorage?.decodeBool(AppConfig.PREF_START_SCAN_IMMEDIATE) == true) {
32 | launchScan()
33 | }
34 | supportActionBar?.setTitle("Scan QrCode")
35 |
36 | }
37 |
38 |
39 |
40 | private fun launchScan(){
41 | scanQrCode.launch(
42 | ScannerConfig.build {
43 | setHapticSuccessFeedback(true) // enable (default) or disable haptic feedback when a barcode was detected
44 | setShowTorchToggle(true) // show or hide (default) torch/flashlight toggle button
45 | setShowCloseButton(true) // show or hide (default) close button
46 | }
47 | )
48 | }
49 |
50 | private fun handleResult(result: QRResult) {
51 | if (result is QRResult.QRSuccess ) {
52 | finished(result.content.rawValue)
53 | } else {
54 | finish()
55 | }
56 | }
57 |
58 | private fun finished(text: String) {
59 | val intent = Intent()
60 | intent.putExtra("SCAN_RESULT", text)
61 | setResult(Activity.RESULT_OK, intent)
62 | finish()
63 | }
64 |
65 | override fun onCreateOptionsMenu(menu: Menu): Boolean {
66 | menuInflater.inflate(R.menu.menu_scanner, menu)
67 | return true
68 | }
69 |
70 | override fun onOptionsItemSelected(item: MenuItem) = when (item.itemId) {
71 | R.id.scan_code -> {
72 | launchScan()
73 | true
74 | }
75 | R.id.select_photo -> {
76 | val permission = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
77 | Manifest.permission.READ_MEDIA_IMAGES
78 | } else {
79 | Manifest.permission.READ_EXTERNAL_STORAGE
80 | }
81 | RxPermissions(this)
82 | .request(permission)
83 | .subscribe {
84 | if (it) {
85 | try {
86 | showFileChooser()
87 | } catch (e: Exception) {
88 | e.printStackTrace()
89 | }
90 | } else
91 | toast(R.string.toast_permission_denied)
92 | }
93 | true
94 | }
95 | else -> super.onOptionsItemSelected(item)
96 | }
97 |
98 | private fun showFileChooser() {
99 | val intent = Intent(Intent.ACTION_GET_CONTENT)
100 | intent.type = "image/*"
101 | intent.addCategory(Intent.CATEGORY_OPENABLE)
102 | //intent.putExtra(Intent.EXTRA_ALLOW_MULTIPLE, true)
103 |
104 | try {
105 | chooseFile.launch(Intent.createChooser(intent, getString(R.string.title_file_chooser)))
106 | } catch (ex: android.content.ActivityNotFoundException) {
107 | toast(R.string.toast_require_file_manager)
108 | }
109 | }
110 |
111 | private val chooseFile = registerForActivityResult(ActivityResultContracts.StartActivityForResult()) {
112 | val uri = it.data?.data
113 | if (it.resultCode == RESULT_OK && uri != null) {
114 | try {
115 | val bitmap = BitmapFactory.decodeStream(contentResolver.openInputStream(uri))
116 | val text = QRCodeDecoder.syncDecodeQRCode(bitmap)
117 | finished(text!!)
118 | } catch (e: Exception) {
119 | e.printStackTrace()
120 | toast(e.message.toString())
121 | }
122 | }
123 | }
124 | }
125 |
--------------------------------------------------------------------------------
/app/src/main/kotlin/com/agn/v2ray/ui/SubEditActivity.kt:
--------------------------------------------------------------------------------
1 | package com.agn.v2ray.ui
2 |
3 | import android.os.Bundle
4 | import android.text.TextUtils
5 | import android.view.Menu
6 | import android.view.MenuItem
7 | import androidx.appcompat.app.AlertDialog
8 | import com.google.gson.Gson
9 | import com.tencent.mmkv.MMKV
10 | import com.agn.v2ray.R
11 | import com.agn.v2ray.databinding.ActivitySubEditBinding
12 | import com.agn.v2ray.dto.SubscriptionItem
13 | import com.agn.v2ray.extension.toast
14 | import com.agn.v2ray.util.MmkvManager
15 | import com.agn.v2ray.util.Utils
16 |
17 | class SubEditActivity : BaseActivity() {
18 | private lateinit var binding: ActivitySubEditBinding
19 |
20 | var del_config: MenuItem? = null
21 | var save_config: MenuItem? = null
22 |
23 | private val subStorage by lazy { MMKV.mmkvWithID(MmkvManager.ID_SUB, MMKV.MULTI_PROCESS_MODE) }
24 | private val editSubId by lazy { intent.getStringExtra("subId").orEmpty() }
25 |
26 | override fun onCreate(savedInstanceState: Bundle?) {
27 | super.onCreate(savedInstanceState)
28 | binding = ActivitySubEditBinding.inflate(layoutInflater)
29 | val view = binding.root
30 | setContentView(view)
31 | title = getString(R.string.title_sub_setting)
32 |
33 | val json = subStorage?.decodeString(editSubId)
34 | if (!json.isNullOrBlank()) {
35 | bindingServer(Gson().fromJson(json, SubscriptionItem::class.java))
36 | } else {
37 | clearServer()
38 | }
39 |
40 | }
41 |
42 | /**
43 | * bingding seleced server config
44 | */
45 | private fun bindingServer(subItem: SubscriptionItem): Boolean {
46 | binding.etRemarks.text = Utils.getEditable(subItem.remarks)
47 | binding.etUrl.text = Utils.getEditable(subItem.url)
48 | binding.chkEnable.isChecked = subItem.enabled
49 | return true
50 | }
51 |
52 | /**
53 | * clear or init server config
54 | */
55 | private fun clearServer(): Boolean {
56 | binding.etRemarks.text = null
57 | binding.etUrl.text = null
58 | binding.chkEnable.isChecked = true
59 | return true
60 | }
61 |
62 | /**
63 | * save server config
64 | */
65 | private fun saveServer(): Boolean {
66 | val subItem: SubscriptionItem
67 | val json = subStorage?.decodeString(editSubId)
68 | var subId = editSubId
69 | if (!json.isNullOrBlank()) {
70 | subItem = Gson().fromJson(json, SubscriptionItem::class.java)
71 | } else {
72 | subId = Utils.getUuid()
73 | subItem = SubscriptionItem()
74 | }
75 |
76 | subItem.remarks = binding.etRemarks.text.toString()
77 | subItem.url = binding.etUrl.text.toString()
78 | subItem.enabled = binding.chkEnable.isChecked
79 |
80 | if (TextUtils.isEmpty(subItem.remarks)) {
81 | toast(R.string.sub_setting_remarks)
82 | return false
83 | }
84 | // if (TextUtils.isEmpty(subItem.url)) {
85 | // toast(R.string.sub_setting_url)
86 | // return false
87 | // }
88 |
89 | subStorage?.encode(subId, Gson().toJson(subItem))
90 | toast(R.string.toast_success)
91 | finish()
92 | return true
93 | }
94 |
95 | /**
96 | * save server config
97 | */
98 | private fun deleteServer(): Boolean {
99 | if (editSubId.isNotEmpty()) {
100 | AlertDialog.Builder(this).setMessage(R.string.del_config_comfirm)
101 | .setPositiveButton(android.R.string.ok) { _, _ ->
102 | MmkvManager.removeSubscription(editSubId)
103 | finish()
104 | }
105 | .show()
106 | }
107 | return true
108 | }
109 |
110 | override fun onCreateOptionsMenu(menu: Menu): Boolean {
111 | menuInflater.inflate(R.menu.action_server, menu)
112 | del_config = menu.findItem(R.id.del_config)
113 | save_config = menu.findItem(R.id.save_config)
114 |
115 | if (editSubId.isEmpty()) {
116 | del_config?.isVisible = false
117 | }
118 |
119 | return super.onCreateOptionsMenu(menu)
120 | }
121 |
122 | override fun onOptionsItemSelected(item: MenuItem) = when (item.itemId) {
123 | R.id.del_config -> {
124 | deleteServer()
125 | true
126 | }
127 | R.id.save_config -> {
128 | saveServer()
129 | true
130 | }
131 | else -> super.onOptionsItemSelected(item)
132 | }
133 | }
134 |
--------------------------------------------------------------------------------
/app/src/main/kotlin/com/agn/v2ray/ui/SubSettingActivity.kt:
--------------------------------------------------------------------------------
1 | package com.agn.v2ray.ui
2 |
3 | import android.content.Intent
4 | import androidx.recyclerview.widget.LinearLayoutManager
5 | import android.view.Menu
6 | import android.view.MenuItem
7 | import com.agn.v2ray.R
8 | import android.os.Bundle
9 | import com.agn.v2ray.databinding.ActivitySubSettingBinding
10 | import com.agn.v2ray.dto.SubscriptionItem
11 | import com.agn.v2ray.util.MmkvManager
12 |
13 | class SubSettingActivity : BaseActivity() {
14 | private lateinit var binding: ActivitySubSettingBinding
15 |
16 | var subscriptions:List> = listOf()
17 | private val adapter by lazy { SubSettingRecyclerAdapter(this) }
18 |
19 | override fun onCreate(savedInstanceState: Bundle?) {
20 | super.onCreate(savedInstanceState)
21 | binding = ActivitySubSettingBinding.inflate(layoutInflater)
22 | val view = binding.root
23 | setContentView(view)
24 |
25 | title = getString(R.string.title_sub_setting)
26 |
27 | binding.recyclerView.setHasFixedSize(true)
28 | binding.recyclerView.layoutManager = LinearLayoutManager(this)
29 | binding.recyclerView.adapter = adapter
30 |
31 |
32 | }
33 |
34 | override fun onResume() {
35 | super.onResume()
36 | subscriptions = MmkvManager.decodeSubscriptions()
37 | adapter.notifyDataSetChanged()
38 | }
39 |
40 | override fun onCreateOptionsMenu(menu: Menu): Boolean {
41 | menuInflater.inflate(R.menu.action_sub_setting, menu)
42 | menu.findItem(R.id.del_config)?.isVisible = false
43 | menu.findItem(R.id.save_config)?.isVisible = false
44 |
45 | return super.onCreateOptionsMenu(menu)
46 | }
47 |
48 | override fun onOptionsItemSelected(item: MenuItem) = when (item.itemId) {
49 | R.id.add_config -> {
50 | startActivity(Intent(this, SubEditActivity::class.java))
51 | true
52 | }
53 | else -> super.onOptionsItemSelected(item)
54 | }
55 | }
56 |
--------------------------------------------------------------------------------
/app/src/main/kotlin/com/agn/v2ray/ui/SubSettingRecyclerAdapter.kt:
--------------------------------------------------------------------------------
1 | package com.agn.v2ray.ui
2 |
3 | import android.content.Intent
4 | import android.graphics.Color
5 | import android.text.TextUtils
6 | import android.view.LayoutInflater
7 | import android.view.View
8 | import androidx.recyclerview.widget.RecyclerView
9 | import android.view.ViewGroup
10 | import androidx.appcompat.app.AlertDialog
11 | import com.google.gson.Gson
12 | import com.tencent.mmkv.MMKV
13 | import com.agn.v2ray.R
14 | import com.agn.v2ray.databinding.ItemQrcodeBinding
15 | import com.agn.v2ray.databinding.ItemRecyclerSubSettingBinding
16 | import com.agn.v2ray.dto.EConfigType
17 | import com.agn.v2ray.extension.toast
18 | import com.agn.v2ray.util.AngConfigManager
19 | import com.agn.v2ray.util.MmkvManager
20 | import com.agn.v2ray.util.QRCodeDecoder
21 | import com.agn.v2ray.util.Utils
22 |
23 | class SubSettingRecyclerAdapter(val activity: SubSettingActivity) :
24 | RecyclerView.Adapter() {
25 |
26 | private var mActivity: SubSettingActivity = activity
27 | private val subStorage by lazy { MMKV.mmkvWithID(MmkvManager.ID_SUB, MMKV.MULTI_PROCESS_MODE) }
28 |
29 | private val share_method: Array by lazy {
30 | mActivity.resources.getStringArray(R.array.share_sub_method)
31 | }
32 |
33 | override fun getItemCount() = mActivity.subscriptions.size
34 |
35 | override fun onBindViewHolder(holder: MainViewHolder, position: Int) {
36 | val subId = mActivity.subscriptions[position].first
37 | val subItem = mActivity.subscriptions[position].second
38 | holder.itemSubSettingBinding.tvName.text = subItem.remarks
39 | holder.itemSubSettingBinding.tvUrl.text = subItem.url
40 | if (subItem.enabled) {
41 | holder.itemSubSettingBinding.chkEnable.setBackgroundResource(R.color.colorSelected)
42 | } else {
43 | holder.itemSubSettingBinding.chkEnable.setBackgroundResource(R.color.colorUnselected)
44 | }
45 | holder.itemView.setBackgroundColor(Color.TRANSPARENT)
46 |
47 | holder.itemSubSettingBinding.layoutEdit.setOnClickListener {
48 | mActivity.startActivity(
49 | Intent(mActivity, SubEditActivity::class.java)
50 | .putExtra("subId", subId)
51 | )
52 | }
53 | holder.itemSubSettingBinding.infoContainer.setOnClickListener {
54 | subItem.enabled = !subItem.enabled
55 | subStorage?.encode(subId, Gson().toJson(subItem))
56 | notifyItemChanged(position)
57 | }
58 |
59 | if (TextUtils.isEmpty(subItem.url)) {
60 | holder.itemSubSettingBinding.layoutShare.visibility = View.INVISIBLE
61 | } else {
62 | holder.itemSubSettingBinding.layoutShare.setOnClickListener {
63 | AlertDialog.Builder(mActivity)
64 | .setItems(share_method.asList().toTypedArray()) { _, i ->
65 | try {
66 | when (i) {
67 | 0 -> {
68 | val ivBinding =
69 | ItemQrcodeBinding.inflate(LayoutInflater.from(mActivity))
70 | ivBinding.ivQcode.setImageBitmap(
71 | QRCodeDecoder.createQRCode(
72 | subItem.url
73 |
74 | )
75 | )
76 | AlertDialog.Builder(mActivity).setView(ivBinding.root).show()
77 | }
78 |
79 | 1 -> {
80 | Utils.setClipboard(mActivity, subItem.url)
81 | }
82 |
83 | else -> mActivity.toast("else")
84 | }
85 | } catch (e: Exception) {
86 | e.printStackTrace()
87 | }
88 | }.show()
89 | }
90 | }
91 | }
92 |
93 | override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): MainViewHolder {
94 | return MainViewHolder(
95 | ItemRecyclerSubSettingBinding.inflate(
96 | LayoutInflater.from(parent.context),
97 | parent,
98 | false
99 | )
100 | )
101 | }
102 |
103 | class MainViewHolder(val itemSubSettingBinding: ItemRecyclerSubSettingBinding) :
104 | RecyclerView.ViewHolder(itemSubSettingBinding.root)
105 | }
106 |
--------------------------------------------------------------------------------
/app/src/main/kotlin/com/agn/v2ray/ui/TaskerActivity.kt:
--------------------------------------------------------------------------------
1 | package com.agn.v2ray.ui
2 |
3 | import android.app.Activity
4 | import android.os.Bundle
5 | import android.view.View
6 | import android.widget.ArrayAdapter
7 | import android.widget.ListView
8 | import java.util.ArrayList
9 | import com.agn.v2ray.R
10 | import android.content.Intent
11 | import android.text.TextUtils
12 | import android.view.Menu
13 | import android.view.MenuItem
14 | import com.google.zxing.WriterException
15 | import com.tencent.mmkv.MMKV
16 | import com.agn.v2ray.AppConfig
17 | import com.agn.v2ray.databinding.ActivityTaskerBinding
18 | import com.agn.v2ray.util.MmkvManager
19 |
20 | class TaskerActivity : BaseActivity() {
21 | private lateinit var binding: ActivityTaskerBinding
22 |
23 | private var listview: ListView? = null
24 | private var lstData: ArrayList = ArrayList()
25 | private var lstGuid: ArrayList = ArrayList()
26 |
27 | private val serverStorage by lazy { MMKV.mmkvWithID(MmkvManager.ID_SERVER_CONFIG, MMKV.MULTI_PROCESS_MODE) }
28 |
29 | override fun onCreate(savedInstanceState: Bundle?) {
30 | super.onCreate(savedInstanceState)
31 | binding = ActivityTaskerBinding.inflate(layoutInflater)
32 | val view = binding.root
33 | setContentView(view)
34 |
35 | //add def value
36 | lstData.add("Default")
37 | lstGuid.add(AppConfig.TASKER_DEFAULT_GUID)
38 |
39 | serverStorage?.allKeys()?.forEach { key ->
40 | MmkvManager.decodeServerConfig(key)?.let { config ->
41 | lstData.add(config.remarks)
42 | lstGuid.add(key)
43 | }
44 | }
45 | val adapter = ArrayAdapter(this,
46 | android.R.layout.simple_list_item_single_choice, lstData)
47 | listview = findViewById(R.id.listview) as ListView
48 | listview!!.adapter = adapter
49 |
50 | init()
51 | }
52 |
53 | private fun init() {
54 | try {
55 | val bundle = intent?.getBundleExtra(AppConfig.TASKER_EXTRA_BUNDLE)
56 | val switch = bundle?.getBoolean(AppConfig.TASKER_EXTRA_BUNDLE_SWITCH, false)
57 | val guid = bundle?.getString(AppConfig.TASKER_EXTRA_BUNDLE_GUID, "")
58 |
59 | if (switch == null || TextUtils.isEmpty(guid)) {
60 | return
61 | } else {
62 | binding.switchStartService.isChecked = switch
63 | val pos = lstGuid.indexOf(guid.toString())
64 | if (pos >= 0) {
65 | listview?.setItemChecked(pos, true)
66 | }
67 | }
68 | } catch (e: WriterException) {
69 | e.printStackTrace()
70 |
71 | }
72 | }
73 |
74 | private fun confirmFinish() {
75 | val position = listview?.checkedItemPosition
76 | if (position == null || position < 0) {
77 | return
78 | }
79 |
80 | val extraBundle = Bundle()
81 | extraBundle.putBoolean(AppConfig.TASKER_EXTRA_BUNDLE_SWITCH, binding.switchStartService.isChecked)
82 | extraBundle.putString(AppConfig.TASKER_EXTRA_BUNDLE_GUID, lstGuid[position])
83 | val intent = Intent()
84 |
85 | val remarks = lstData[position]
86 | val blurb = if (binding.switchStartService.isChecked) {
87 | "Start $remarks"
88 | } else {
89 | "Stop $remarks"
90 | }
91 |
92 | intent.putExtra(AppConfig.TASKER_EXTRA_BUNDLE, extraBundle)
93 | intent.putExtra(AppConfig.TASKER_EXTRA_STRING_BLURB, blurb)
94 | setResult(Activity.RESULT_OK, intent)
95 | finish()
96 | }
97 |
98 | override fun onCreateOptionsMenu(menu: Menu): Boolean {
99 | menuInflater.inflate(R.menu.action_server, menu)
100 | val del_config = menu.findItem(R.id.del_config)
101 | del_config?.isVisible = false
102 | return super.onCreateOptionsMenu(menu)
103 | }
104 |
105 | override fun onOptionsItemSelected(item: MenuItem) = when (item.itemId) {
106 | R.id.del_config -> {
107 | true
108 | }
109 | R.id.save_config -> {
110 | confirmFinish()
111 | true
112 | }
113 | else -> super.onOptionsItemSelected(item)
114 | }
115 |
116 | }
117 |
118 |
--------------------------------------------------------------------------------
/app/src/main/kotlin/com/agn/v2ray/ui/UrlSchemeActivity.kt:
--------------------------------------------------------------------------------
1 | package com.agn.v2ray.ui
2 |
3 | import android.content.Intent
4 | import android.net.Uri
5 | import android.os.Bundle
6 | import com.google.zxing.WriterException
7 | import com.agn.v2ray.R
8 | import com.agn.v2ray.databinding.ActivityLogcatBinding
9 | import com.agn.v2ray.extension.toast
10 | import com.agn.v2ray.util.AngConfigManager
11 |
12 | class UrlSchemeActivity : BaseActivity() {
13 | private lateinit var binding: ActivityLogcatBinding
14 |
15 | override fun onCreate(savedInstanceState: Bundle?) {
16 | super.onCreate(savedInstanceState)
17 | binding = ActivityLogcatBinding.inflate(layoutInflater)
18 | val view = binding.root
19 | setContentView(view)
20 |
21 | var shareUrl: String = ""
22 | try {
23 | intent?.apply {
24 | when (action) {
25 | Intent.ACTION_SEND -> {
26 | if ("text/plain" == type) {
27 | intent.getStringExtra(Intent.EXTRA_TEXT)?.let {
28 | shareUrl = it
29 | }
30 | }
31 | }
32 | Intent.ACTION_VIEW -> {
33 | val uri: Uri? = intent.data
34 | shareUrl = uri?.getQueryParameter("url")!!
35 | }
36 | }
37 | }
38 | toast(shareUrl)
39 | val count = AngConfigManager.importBatchConfig(shareUrl, "", false)
40 | if (count > 0) {
41 | toast(R.string.toast_success)
42 | } else {
43 | toast(R.string.toast_failure)
44 | }
45 | startActivity(Intent(this, MainActivity::class.java))
46 | finish()
47 | } catch (e: WriterException) {
48 | e.printStackTrace()
49 | }
50 | }
51 | }
--------------------------------------------------------------------------------
/app/src/main/kotlin/com/agn/v2ray/util/AppManagerUtil.kt:
--------------------------------------------------------------------------------
1 | package com.agn.v2ray.util
2 |
3 | import android.Manifest
4 | import android.content.Context
5 | import android.content.pm.ApplicationInfo
6 | import android.content.pm.PackageInfo
7 | import android.content.pm.PackageManager
8 | import com.agn.v2ray.dto.AppInfo
9 | import rx.Observable
10 | import java.util.*
11 |
12 | object AppManagerUtil {
13 | fun loadNetworkAppList(ctx: Context): ArrayList {
14 | val packageManager = ctx.packageManager
15 | val packages = packageManager.getInstalledPackages(PackageManager.GET_PERMISSIONS)
16 | val apps = ArrayList()
17 |
18 | for (pkg in packages) {
19 | if (!pkg.hasInternetPermission && pkg.packageName != "android") continue
20 |
21 | val applicationInfo = pkg.applicationInfo
22 |
23 | val appName = applicationInfo.loadLabel(packageManager).toString()
24 | val appIcon = applicationInfo.loadIcon(packageManager)
25 | val isSystemApp = (applicationInfo.flags and ApplicationInfo.FLAG_SYSTEM) > 0
26 |
27 | val appInfo = AppInfo(appName, pkg.packageName, appIcon, isSystemApp, 0)
28 | apps.add(appInfo)
29 | }
30 |
31 | return apps
32 | }
33 |
34 | fun rxLoadNetworkAppList(ctx: Context): Observable> = Observable.unsafeCreate {
35 | it.onNext(loadNetworkAppList(ctx))
36 | }
37 |
38 | val PackageInfo.hasInternetPermission: Boolean
39 | get() {
40 | val permissions = requestedPermissions
41 | return permissions?.any { it == Manifest.permission.INTERNET } ?: false
42 | }
43 | }
44 |
--------------------------------------------------------------------------------
/app/src/main/kotlin/com/agn/v2ray/util/LanguageHelper.kt:
--------------------------------------------------------------------------------
1 | package com.agn.v2ray.util
2 |
3 | import android.content.Context
4 | import android.content.res.Configuration
5 | import java.util.Locale
6 |
7 | object LanguageHelper {
8 | fun updateContextLocale(context: Context, language: String): Context {
9 | val locale = Locale(language)
10 | Locale.setDefault(locale)
11 | val config = Configuration(context.resources.configuration)
12 | config.setLocale(locale)
13 | return context.createConfigurationContext(config)
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/app/src/main/kotlin/com/agn/v2ray/util/LanguagePrefs.kt:
--------------------------------------------------------------------------------
1 | package com.agn.v2ray.util
2 |
3 | import android.content.Context
4 |
5 | class LanguagePrefs(context: Context) {
6 | private val prefs = context.getSharedPreferences("MyAppPrefs", Context.MODE_PRIVATE)
7 |
8 | fun getSelectedLanguage(): String {
9 | return prefs.getString("selected_language", "auto") ?: "auto"
10 | }
11 |
12 | fun setSelectedLanguage(language: String) {
13 | prefs.edit().putString("selected_language", language).apply()
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/app/src/main/kotlin/com/agn/v2ray/util/MessageUtil.kt:
--------------------------------------------------------------------------------
1 | package com.agn.v2ray.util
2 |
3 | import android.content.ComponentName
4 | import android.content.Context
5 | import android.content.Intent
6 | import com.agn.v2ray.AppConfig
7 | import com.agn.v2ray.service.V2RayTestService
8 | import java.io.Serializable
9 |
10 |
11 | object MessageUtil {
12 |
13 | fun sendMsg2Service(ctx: Context, what: Int, content: Serializable) {
14 | sendMsg(ctx, AppConfig.BROADCAST_ACTION_SERVICE, what, content)
15 | }
16 |
17 | fun sendMsg2UI(ctx: Context, what: Int, content: Serializable) {
18 | sendMsg(ctx, AppConfig.BROADCAST_ACTION_ACTIVITY, what, content)
19 | }
20 |
21 | fun sendMsg2TestService(ctx: Context, what: Int, content: Serializable) {
22 | try {
23 | val intent = Intent()
24 | intent.component = ComponentName(ctx, V2RayTestService::class.java)
25 | intent.putExtra("key", what)
26 | intent.putExtra("content", content)
27 | ctx.startService(intent)
28 | } catch (e: Exception) {
29 | e.printStackTrace()
30 | }
31 | }
32 |
33 | private fun sendMsg(ctx: Context, action: String, what: Int, content: Serializable) {
34 | try {
35 | val intent = Intent()
36 | intent.action = action
37 | intent.`package` = AppConfig.ANG_PACKAGE
38 | intent.putExtra("key", what)
39 | intent.putExtra("content", content)
40 | ctx.sendBroadcast(intent)
41 | } catch (e: Exception) {
42 | e.printStackTrace()
43 | }
44 | }
45 | }
46 |
--------------------------------------------------------------------------------
/app/src/main/kotlin/com/agn/v2ray/util/MyContextWrapper.kt:
--------------------------------------------------------------------------------
1 | package com.agn.v2ray.util
2 |
3 | import android.content.Context
4 | import java.util.Locale
5 |
6 | object MyContextWrapper {
7 | fun wrap(context: Context): Context {
8 | val languagePrefs = LanguagePrefs(context)
9 | val language = languagePrefs.getSelectedLanguage()
10 | val locale = when (language) {
11 | "auto" -> Utils.getSysLocale()
12 | "en" -> Locale("en")
13 | "zh-rCN" -> Locale("zh", "CN")
14 | "zh-rTW" -> Locale("zh", "TW")
15 | "vi" -> Locale("vi")
16 | "ru" -> Locale("ru")
17 | "fa" -> Locale("fa")
18 | "ar" -> Locale("ar")
19 | "es" -> Locale("es")
20 | "de" -> Locale("de")
21 | "th" -> Locale("th")
22 | "fr" -> Locale("fr")
23 | "pt" -> Locale("pt")
24 | "lt" -> Locale("lt")
25 |
26 | else -> Utils.getSysLocale()
27 |
28 | }
29 | val configuration = context.resources.configuration
30 | configuration.setLocale(locale)
31 | return context.createConfigurationContext(configuration)
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/app/src/main/kotlin/com/agn/v2ray/util/QRCodeDecoder.kt:
--------------------------------------------------------------------------------
1 | package com.agn.v2ray.util
2 |
3 | import android.graphics.Bitmap
4 | import android.graphics.BitmapFactory
5 | import com.google.zxing.*
6 | import com.google.zxing.common.GlobalHistogramBinarizer
7 | import com.google.zxing.common.HybridBinarizer
8 | import com.google.zxing.qrcode.QRCodeWriter
9 | import java.util.*
10 |
11 | /**
12 | * 描述:解析二维码图片
13 | */
14 | object QRCodeDecoder {
15 | val HINTS: MutableMap = EnumMap(DecodeHintType::class.java)
16 |
17 | /**
18 | * create qrcode using zxing
19 | */
20 | fun createQRCode(text: String, size: Int = 800): Bitmap? {
21 | try {
22 | val hints = HashMap()
23 | hints[EncodeHintType.CHARACTER_SET] = "utf-8"
24 | val bitMatrix = QRCodeWriter().encode(text,
25 | BarcodeFormat.QR_CODE, size, size, hints)
26 | val pixels = IntArray(size * size)
27 | for (y in 0 until size) {
28 | for (x in 0 until size) {
29 | if (bitMatrix.get(x, y)) {
30 | pixels[y * size + x] = 0xff000000.toInt()
31 | } else {
32 | pixels[y * size + x] = 0xffffffff.toInt()
33 | }
34 |
35 | }
36 | }
37 | val bitmap = Bitmap.createBitmap(size, size,
38 | Bitmap.Config.ARGB_8888)
39 | bitmap.setPixels(pixels, 0, size, 0, 0, size, size)
40 | return bitmap
41 | } catch (e: Exception) {
42 | e.printStackTrace()
43 | return null
44 | }
45 | }
46 |
47 | /**
48 | * 同步解析本地图片二维码。该方法是耗时操作,请在子线程中调用。
49 | *
50 | * @param picturePath 要解析的二维码图片本地路径
51 | * @return 返回二维码图片里的内容 或 null
52 | */
53 | fun syncDecodeQRCode(picturePath: String): String? {
54 | return syncDecodeQRCode(getDecodeAbleBitmap(picturePath))
55 | }
56 |
57 | /**
58 | * 同步解析bitmap二维码。该方法是耗时操作,请在子线程中调用。
59 | *
60 | * @param bitmap 要解析的二维码图片
61 | * @return 返回二维码图片里的内容 或 null
62 | */
63 | fun syncDecodeQRCode(bitmap: Bitmap?): String? {
64 | var source: RGBLuminanceSource? = null
65 | try {
66 | val width = bitmap!!.width
67 | val height = bitmap.height
68 | val pixels = IntArray(width * height)
69 | bitmap.getPixels(pixels, 0, width, 0, 0, width, height)
70 | source = RGBLuminanceSource(width, height, pixels)
71 | return MultiFormatReader().decode(BinaryBitmap(HybridBinarizer(source)), HINTS).text
72 | } catch (e: Exception) {
73 | e.printStackTrace()
74 | }
75 | if (source != null) {
76 | try {
77 | return MultiFormatReader().decode(BinaryBitmap(GlobalHistogramBinarizer(source)), HINTS).text
78 | } catch (e2: Throwable) {
79 | e2.printStackTrace()
80 | }
81 | }
82 | return null
83 | }
84 |
85 | /**
86 | * 将本地图片文件转换成可解码二维码的 Bitmap。为了避免图片太大,这里对图片进行了压缩。感谢 https://github.com/devilsen 提的 PR
87 | *
88 | * @param picturePath 本地图片文件路径
89 | * @return
90 | */
91 | private fun getDecodeAbleBitmap(picturePath: String): Bitmap? {
92 | return try {
93 | val options = BitmapFactory.Options()
94 | options.inJustDecodeBounds = true
95 | BitmapFactory.decodeFile(picturePath, options)
96 | var sampleSize = options.outHeight / 400
97 | if (sampleSize <= 0) {
98 | sampleSize = 1
99 | }
100 | options.inSampleSize = sampleSize
101 | options.inJustDecodeBounds = false
102 | BitmapFactory.decodeFile(picturePath, options)
103 | } catch (e: Exception) {
104 | null
105 | }
106 | }
107 |
108 | init {
109 | val allFormats: List = arrayListOf(
110 | BarcodeFormat.AZTEC
111 | ,BarcodeFormat.CODABAR
112 | ,BarcodeFormat.CODE_39
113 | ,BarcodeFormat.CODE_93
114 | ,BarcodeFormat.CODE_128
115 | ,BarcodeFormat.DATA_MATRIX
116 | ,BarcodeFormat.EAN_8
117 | ,BarcodeFormat.EAN_13
118 | ,BarcodeFormat.ITF
119 | ,BarcodeFormat.MAXICODE
120 | ,BarcodeFormat.PDF_417
121 | ,BarcodeFormat.QR_CODE
122 | ,BarcodeFormat.RSS_14
123 | ,BarcodeFormat.RSS_EXPANDED
124 | ,BarcodeFormat.UPC_A
125 | ,BarcodeFormat.UPC_E
126 | ,BarcodeFormat.UPC_EAN_EXTENSION)
127 | HINTS[DecodeHintType.TRY_HARDER] = BarcodeFormat.QR_CODE
128 | HINTS[DecodeHintType.POSSIBLE_FORMATS] = allFormats
129 | HINTS[DecodeHintType.CHARACTER_SET] = "utf-8"
130 | }
131 | }
132 |
--------------------------------------------------------------------------------
/app/src/main/kotlin/com/agn/v2ray/viewmodel/SettingsViewModel.kt:
--------------------------------------------------------------------------------
1 | package com.agn.v2ray.viewmodel
2 |
3 | import android.app.Application
4 | import android.content.SharedPreferences
5 | import android.util.Log
6 | import androidx.lifecycle.AndroidViewModel
7 | import androidx.preference.PreferenceManager
8 | import com.tencent.mmkv.MMKV
9 | import com.agn.v2ray.AppConfig
10 | import com.agn.v2ray.util.MmkvManager
11 |
12 | class SettingsViewModel(application: Application) : AndroidViewModel(application), SharedPreferences.OnSharedPreferenceChangeListener {
13 |
14 | private val settingsStorage by lazy { MMKV.mmkvWithID(MmkvManager.ID_SETTING, MMKV.MULTI_PROCESS_MODE) }
15 |
16 | fun startListenPreferenceChange() {
17 | PreferenceManager.getDefaultSharedPreferences(getApplication()).registerOnSharedPreferenceChangeListener(this)
18 | }
19 |
20 | override fun onCleared() {
21 | PreferenceManager.getDefaultSharedPreferences(getApplication()).unregisterOnSharedPreferenceChangeListener(this)
22 | Log.i(AppConfig.ANG_PACKAGE, "Settings ViewModel is cleared")
23 | super.onCleared()
24 | }
25 |
26 | override fun onSharedPreferenceChanged(sharedPreferences: SharedPreferences, key: String?) {
27 | Log.d(AppConfig.ANG_PACKAGE, "Observe settings changed: $key")
28 | when(key) {
29 | AppConfig.PREF_MODE,
30 | AppConfig.PREF_VPN_DNS,
31 | AppConfig.PREF_REMOTE_DNS,
32 | AppConfig.PREF_DOMESTIC_DNS,
33 | AppConfig.PREF_LOCAL_DNS_PORT,
34 | AppConfig.PREF_SOCKS_PORT,
35 | AppConfig.PREF_HTTP_PORT,
36 | AppConfig.PREF_LOGLEVEL,
37 | AppConfig.PREF_LANGUAGE,
38 | AppConfig.PREF_ROUTING_DOMAIN_STRATEGY,
39 | AppConfig.PREF_ROUTING_MODE,
40 | AppConfig.PREF_V2RAY_ROUTING_AGENT,
41 | AppConfig.PREF_V2RAY_ROUTING_BLOCKED,
42 | AppConfig.PREF_V2RAY_ROUTING_DIRECT,
43 | AppConfig.SUBSCRIPTION_AUTO_UPDATE_INTERVAL,
44 | AppConfig.PREF_MUX_XUDP_QUIC, -> {
45 | settingsStorage?.encode(key, sharedPreferences.getString(key, ""))
46 | }
47 | AppConfig.PREF_SPEED_ENABLED,
48 | AppConfig.PREF_PROXY_SHARING,
49 | AppConfig.PREF_LOCAL_DNS_ENABLED,
50 | AppConfig.PREF_FAKE_DNS_ENABLED,
51 | AppConfig.PREF_ALLOW_INSECURE,
52 | AppConfig.PREF_PREFER_IPV6,
53 | AppConfig.PREF_PER_APP_PROXY,
54 | AppConfig.PREF_BYPASS_APPS,
55 | AppConfig.PREF_CONFIRM_REMOVE,
56 | AppConfig.PREF_START_SCAN_IMMEDIATE,
57 | AppConfig.SUBSCRIPTION_AUTO_UPDATE,
58 | AppConfig.PREF_MUX_ENABLED, -> {
59 | settingsStorage?.encode(key, sharedPreferences.getBoolean(key, false))
60 | }
61 | AppConfig.PREF_SNIFFING_ENABLED -> {
62 | settingsStorage?.encode(key, sharedPreferences.getBoolean(key, true))
63 | }
64 | AppConfig.PREF_MUX_CONCURRENCY,
65 | AppConfig.PREF_MUX_XUDP_CONCURRENCY -> {
66 | settingsStorage?.encode(key, sharedPreferences.getString(key, "8")?.toIntOrNull() ?: 8)
67 | }
68 | AppConfig.PREF_PER_APP_PROXY_SET -> {
69 | settingsStorage?.encode(key, sharedPreferences.getStringSet(key, setOf()))
70 | }
71 | }
72 | }
73 | }
--------------------------------------------------------------------------------
/app/src/main/res/anim/fade_in.xml:
--------------------------------------------------------------------------------
1 |
2 |
7 |
--------------------------------------------------------------------------------
/app/src/main/res/anim/fade_out.xml:
--------------------------------------------------------------------------------
1 |
2 |
7 |
--------------------------------------------------------------------------------
/app/src/main/res/color/color_highlight_material.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable-hdpi/ic_stat_direct.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/khaledagn/V2rayAGN/f348cb956337c1f9cbcc553f4beb0cf0c9f9bed8/app/src/main/res/drawable-hdpi/ic_stat_direct.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-hdpi/ic_stat_name.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/khaledagn/V2rayAGN/f348cb956337c1f9cbcc553f4beb0cf0c9f9bed8/app/src/main/res/drawable-hdpi/ic_stat_name.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-hdpi/ic_stat_proxy.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/khaledagn/V2rayAGN/f348cb956337c1f9cbcc553f4beb0cf0c9f9bed8/app/src/main/res/drawable-hdpi/ic_stat_proxy.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-ldrtl/bg_nav.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 |
7 |
10 |
11 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable-mdpi/ic_stat_direct.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/khaledagn/V2rayAGN/f348cb956337c1f9cbcc553f4beb0cf0c9f9bed8/app/src/main/res/drawable-mdpi/ic_stat_direct.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-mdpi/ic_stat_name.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/khaledagn/V2rayAGN/f348cb956337c1f9cbcc553f4beb0cf0c9f9bed8/app/src/main/res/drawable-mdpi/ic_stat_name.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-mdpi/ic_stat_proxy.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/khaledagn/V2rayAGN/f348cb956337c1f9cbcc553f4beb0cf0c9f9bed8/app/src/main/res/drawable-mdpi/ic_stat_proxy.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xhdpi/ic_stat_direct.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/khaledagn/V2rayAGN/f348cb956337c1f9cbcc553f4beb0cf0c9f9bed8/app/src/main/res/drawable-xhdpi/ic_stat_direct.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xhdpi/ic_stat_name.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/khaledagn/V2rayAGN/f348cb956337c1f9cbcc553f4beb0cf0c9f9bed8/app/src/main/res/drawable-xhdpi/ic_stat_name.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xhdpi/ic_stat_proxy.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/khaledagn/V2rayAGN/f348cb956337c1f9cbcc553f4beb0cf0c9f9bed8/app/src/main/res/drawable-xhdpi/ic_stat_proxy.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xxhdpi/donate.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/khaledagn/V2rayAGN/f348cb956337c1f9cbcc553f4beb0cf0c9f9bed8/app/src/main/res/drawable-xxhdpi/donate.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xxhdpi/ic_stat_direct.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/khaledagn/V2rayAGN/f348cb956337c1f9cbcc553f4beb0cf0c9f9bed8/app/src/main/res/drawable-xxhdpi/ic_stat_direct.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xxhdpi/ic_stat_name.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/khaledagn/V2rayAGN/f348cb956337c1f9cbcc553f4beb0cf0c9f9bed8/app/src/main/res/drawable-xxhdpi/ic_stat_name.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xxhdpi/ic_stat_proxy.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/khaledagn/V2rayAGN/f348cb956337c1f9cbcc553f4beb0cf0c9f9bed8/app/src/main/res/drawable-xxhdpi/ic_stat_proxy.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xxhdpi/side_nav_bar.xml:
--------------------------------------------------------------------------------
1 |
3 |
9 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xxxhdpi/ic_stat_direct.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/khaledagn/V2rayAGN/f348cb956337c1f9cbcc553f4beb0cf0c9f9bed8/app/src/main/res/drawable-xxxhdpi/ic_stat_direct.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xxxhdpi/ic_stat_name.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/khaledagn/V2rayAGN/f348cb956337c1f9cbcc553f4beb0cf0c9f9bed8/app/src/main/res/drawable-xxxhdpi/ic_stat_name.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xxxhdpi/ic_stat_proxy.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/khaledagn/V2rayAGN/f348cb956337c1f9cbcc553f4beb0cf0c9f9bed8/app/src/main/res/drawable-xxxhdpi/ic_stat_proxy.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable/autorenew.xml:
--------------------------------------------------------------------------------
1 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/background_test_button.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
5 |
7 |
9 |
10 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/baseline_privacy_tip_24.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/bg_nav.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 |
7 |
10 |
11 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_action_done.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
10 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_action_done_white.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
10 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_add_black_24dp.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
10 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_add_white_24dp.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
10 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_attach_money_black_24dp.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
10 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_attach_money_white_24dp.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
10 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_autorenew_black_24dp.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/khaledagn/V2rayAGN/f348cb956337c1f9cbcc553f4beb0cf0c9f9bed8/app/src/main/res/drawable/ic_autorenew_black_24dp.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_baseline_add_24.xml:
--------------------------------------------------------------------------------
1 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_baseline_arrow_back_24.xml:
--------------------------------------------------------------------------------
1 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_baseline_filter_alt_24.xml:
--------------------------------------------------------------------------------
1 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_close_grey_800_24dp.xml:
--------------------------------------------------------------------------------
1 |
2 |
7 |
10 |
11 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_cloud_download_white_24dp.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
10 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_copy_white.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
10 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_delete_black_24dp.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
10 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_delete_white_24dp.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
10 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_description_black_24dp.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
10 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_description_white_24dp.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
10 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_edit_black_24dp.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
10 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_fab_check.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
10 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_fab_uncheck.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/khaledagn/V2rayAGN/f348cb956337c1f9cbcc553f4beb0cf0c9f9bed8/app/src/main/res/drawable/ic_fab_uncheck.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_feedback_white_24dp.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
10 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_file_white_24dp.xml:
--------------------------------------------------------------------------------
1 |
6 |
13 |
20 |
27 |
34 |
35 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_image_photo.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
10 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_info.xml:
--------------------------------------------------------------------------------
1 |
2 |
7 |
10 |
11 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_info_black_24dp.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
10 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_logcat_white_24dp.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
10 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_outline_filter_alt_white_24.xml:
--------------------------------------------------------------------------------
1 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_person.xml:
--------------------------------------------------------------------------------
1 |
2 |
7 |
10 |
11 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_plane.xml:
--------------------------------------------------------------------------------
1 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_qu_scan_black_24dp.xml:
--------------------------------------------------------------------------------
1 |
6 |
7 |
10 |
14 |
19 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_qu_switch_black_24dp.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
10 |
11 |
17 |
18 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_rounded_corner_grey.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_rounded_corner_theme.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_save_white_24dp.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
10 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_scan_black_24dp.xml:
--------------------------------------------------------------------------------
1 |
6 |
7 |
10 |
14 |
19 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_select_all_white_24dp.xml:
--------------------------------------------------------------------------------
1 |
2 |
7 |
10 |
11 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_settings_white_24dp.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
10 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_share_black_24dp.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
10 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_share_white_24dp.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
10 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_shortcut_background.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 |
7 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_start_busy.xml:
--------------------------------------------------------------------------------
1 |
6 |
7 |
10 |
13 |
14 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_start_connected.xml:
--------------------------------------------------------------------------------
1 |
6 |
7 |
10 |
13 |
14 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_start_connected_black.xml:
--------------------------------------------------------------------------------
1 |
6 |
7 |
10 |
13 |
14 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_start_idle.xml:
--------------------------------------------------------------------------------
1 |
6 |
7 |
10 |
15 |
18 |
21 |
24 |
25 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_stat_direct.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/khaledagn/V2rayAGN/f348cb956337c1f9cbcc553f4beb0cf0c9f9bed8/app/src/main/res/drawable/ic_stat_direct.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_stat_proxy.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/khaledagn/V2rayAGN/f348cb956337c1f9cbcc553f4beb0cf0c9f9bed8/app/src/main/res/drawable/ic_stat_proxy.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_subscriptions_black_24dp.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
10 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_subscriptions_white_24dp.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
10 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_v.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/khaledagn/V2rayAGN/f348cb956337c1f9cbcc553f4beb0cf0c9f9bed8/app/src/main/res/drawable/ic_v.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_v_connected_black.xml:
--------------------------------------------------------------------------------
1 |
6 |
7 |
10 |
11 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_v_idle.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/khaledagn/V2rayAGN/f348cb956337c1f9cbcc553f4beb0cf0c9f9bed8/app/src/main/res/drawable/ic_v_idle.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_whatshot_black_24dp.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
10 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_whatshot_white_24dp.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
10 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_youtube.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/khaledagn/V2rayAGN/f348cb956337c1f9cbcc553f4beb0cf0c9f9bed8/app/src/main/res/drawable/ic_youtube.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable/icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/khaledagn/V2rayAGN/f348cb956337c1f9cbcc553f4beb0cf0c9f9bed8/app/src/main/res/drawable/icon.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable/nav_header_bg.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/khaledagn/V2rayAGN/f348cb956337c1f9cbcc553f4beb0cf0c9f9bed8/app/src/main/res/drawable/nav_header_bg.png
--------------------------------------------------------------------------------
/app/src/main/res/font/poppins_medium.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/khaledagn/V2rayAGN/f348cb956337c1f9cbcc553f4beb0cf0c9f9bed8/app/src/main/res/font/poppins_medium.ttf
--------------------------------------------------------------------------------
/app/src/main/res/layout/.activity_main.xml.kate-swp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/khaledagn/V2rayAGN/f348cb956337c1f9cbcc553f4beb0cf0c9f9bed8/app/src/main/res/layout/.activity_main.xml.kate-swp
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_bypass_list.xml:
--------------------------------------------------------------------------------
1 |
2 |
8 |
9 |
16 |
17 |
21 |
22 |
26 |
27 |
35 |
36 |
41 |
42 |
47 |
48 |
49 |
50 |
58 |
59 |
65 |
66 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
84 |
85 |
91 |
92 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_logcat.xml:
--------------------------------------------------------------------------------
1 |
2 |
8 |
9 |
16 |
17 |
27 |
28 |
35 |
36 |
37 |
38 |
39 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_none.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_routing_settings.xml:
--------------------------------------------------------------------------------
1 |
6 |
7 |
11 |
12 |
16 |
17 |
18 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_server_custom_config.xml:
--------------------------------------------------------------------------------
1 |
2 |
7 |
8 |
12 |
13 |
18 |
19 |
25 |
26 |
27 |
32 |
33 |
38 |
39 |
40 |
45 |
46 |
50 |
51 |
56 |
57 |
58 |
59 |
63 |
64 |
70 |
71 |
77 |
78 |
79 |
80 |
81 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_settings.xml:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_splash.xml:
--------------------------------------------------------------------------------
1 |
2 |
11 |
12 |
19 |
20 |
31 |
32 |
33 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_sub_setting.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
10 |
11 |
15 |
16 |
21 |
22 |
23 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_tasker.xml:
--------------------------------------------------------------------------------
1 |
8 |
9 |
12 |
13 |
21 |
22 |
32 |
33 |
34 |
35 |
40 |
41 |
46 |
47 |
48 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/daynightswitch.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
8 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/dialog_config_filter.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 |
11 |
12 |
17 |
18 |
22 |
23 |
24 |
25 |
30 |
31 |
35 |
36 |
41 |
42 |
43 |
44 |
45 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/fragment_routing_settings.xml:
--------------------------------------------------------------------------------
1 |
6 |
7 |
10 |
11 |
17 |
18 |
23 |
24 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/item_qrcode.xml:
--------------------------------------------------------------------------------
1 |
2 |
8 |
9 |
15 |
16 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/item_recycler_bypass_list.xml:
--------------------------------------------------------------------------------
1 |
2 |
9 |
10 |
18 |
19 |
27 |
28 |
32 |
33 |
38 |
39 |
40 |
41 |
51 |
52 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/item_recycler_footer.xml:
--------------------------------------------------------------------------------
1 |
2 |
7 |
8 |
16 |
17 |
23 |
24 |
30 |
31 |
32 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/item_recycler_sub_setting.xml:
--------------------------------------------------------------------------------
1 |
2 |
8 |
9 |
16 |
17 |
28 |
29 |
35 |
36 |
42 |
43 |
48 |
49 |
56 |
57 |
58 |
59 |
60 |
65 |
66 |
77 |
78 |
83 |
84 |
85 |
86 |
97 |
98 |
103 |
104 |
105 |
106 |
107 |
108 |
109 |
110 |
111 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/item_recycler_user_asset.xml:
--------------------------------------------------------------------------------
1 |
2 |
7 |
8 |
13 |
14 |
20 |
21 |
26 |
27 |
33 |
34 |
41 |
42 |
43 |
51 |
52 |
57 |
58 |
59 |
60 |
61 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/nav_header.xml:
--------------------------------------------------------------------------------
1 |
2 |
12 |
19 |
20 |
30 |
31 |
32 |
33 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/nav_toolbar.xml:
--------------------------------------------------------------------------------
1 |
2 |
6 |
7 |
12 |
13 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/nav_view.xml:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/preference_with_help_link.xml:
--------------------------------------------------------------------------------
1 |
2 |
12 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/widget_switch.xml:
--------------------------------------------------------------------------------
1 |
2 |
9 |
10 |
15 |
16 |
--------------------------------------------------------------------------------
/app/src/main/res/menu/action_server.xml:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/app/src/main/res/menu/action_sub_setting.xml:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/app/src/main/res/menu/menu_asset.xml:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/app/src/main/res/menu/menu_bypass_list.xml:
--------------------------------------------------------------------------------
1 |
2 |
35 |
--------------------------------------------------------------------------------
/app/src/main/res/menu/menu_drawer.xml:
--------------------------------------------------------------------------------
1 |
2 |
49 |
--------------------------------------------------------------------------------
/app/src/main/res/menu/menu_logcat.xml:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/app/src/main/res/menu/menu_routing.xml:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/app/src/main/res/menu/menu_scanner.xml:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/app/src/main/res/raw/licenses.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | Android Compatibility Library v4
4 | http://source.android.com
5 | Copyright(C) 2008-2011 The Android Open Source Project
6 | Apache Software License 2.0
7 |
8 |
9 | Android Compatibility Library v7
10 | http://source.android.com
11 | Copyright(C) 2008-2011 The Android Open Source Project
12 | Apache Software License 2.0
13 |
14 |
15 | Android Design Library
16 | http://source.android.com
17 | Copyright(C) 2008-2011 The Android Open Source Project
18 | Apache Software License 2.0
19 |
20 |
21 | Google Gson
22 | https://github.com/google/gson
23 | Copyright 2008-2011 Google Inc.
24 | Apache Software License 2.0
25 |
26 |
27 | kotlin
28 | http://kotlinlang.org/
29 | Copyright 2010-2016 JetBrains s.r.o.
30 | Apache Software License 2.0
31 |
32 |
33 | Logger
34 | https://github.com/orhanobut/logger
35 | Copyright 2015 Orhan Obut
36 | Apache Software License 2.0
37 |
38 |
39 | LeakCanary
40 | https://github.com/square/leakcanary
41 | Copyright 2015 Square, Inc.
42 | Apache Software License 2.0
43 |
44 |
45 | RxPermissions
46 | https://github.com/tbruyelle/RxPermissions
47 | Apache Software License 2.0
48 |
49 |
50 |
--------------------------------------------------------------------------------
/app/src/main/res/values-night/colors.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | #ff8000
4 | #ff8000
5 | #ff9800
6 | #ff8000
7 | #ff9000
8 | #fff
9 | #222
10 | #fff
11 | #f9f9f9
12 | #303030
13 |
14 |
--------------------------------------------------------------------------------
/app/src/main/res/values-sw360dp-v13/values-preference.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | false
4 | 0dp
5 |
--------------------------------------------------------------------------------
/app/src/main/res/values/attrs.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/app/src/main/res/values/colors.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | #FF0099
4 | #ff8000
5 | #999999
6 | #CFD8DC
7 | #212121
8 | #f97910
9 |
10 | #ff8000
11 | #ff8000
12 | #ff9800
13 | #ff8000
14 | #ff9000
15 | #212121
16 | #757575
17 | #111
18 | #BDBDBD
19 | #ff8000
20 | #ff8000
21 | #ffffff
22 | #ffffff
23 |
24 | #ff8000
25 | #FFFFFF
26 | #000000
27 | #000
28 | #111
29 |
30 | #ff8000
31 | #ff8000
32 | #ff8000
33 | #ff8000
34 | #CCCCCC
35 |
36 |
--------------------------------------------------------------------------------
/app/src/main/res/values/dimens.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | 50dp
4 | 16dp
5 | 16dp
6 | 8dp
7 | 50dp
8 | 24dp
9 | 72dp
10 | 60dp
11 |
12 | 16dp
13 | 16dp
14 | 8dp
15 | 160dp
16 |
17 |
--------------------------------------------------------------------------------
/app/src/main/res/values/ic_launcher_background.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | #FFFFFF
4 |
--------------------------------------------------------------------------------
/app/src/main/res/values/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
13 |
16 |
17 |
18 |
21 |
22 |
23 |
26 |
27 |
30 |
39 |
42 |
45 |
48 |
56 |
57 |
58 |
64 |
65 |
70 |
71 |
76 |
77 |
78 |
79 |
80 |
81 |
--------------------------------------------------------------------------------
/app/src/main/res/xml/app_widget_provider.xml:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/app/src/main/res/xml/shortcuts.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
10 |
11 |
15 |
16 |
17 |
24 |
25 |
29 |
30 |
31 |
38 |
39 |
43 |
44 |
45 |
--------------------------------------------------------------------------------
/app/src/test/java/com/agn/v2ray/ExampleUnitTest.java:
--------------------------------------------------------------------------------
1 | package com.agn.v2ray;
2 |
3 | import org.junit.Test;
4 |
5 | import static org.junit.Assert.assertEquals;
6 |
7 | /**
8 | * To work on unit tests, switch the Test Artifact in the Build Variants view.
9 | */
10 | public class ExampleUnitTest {
11 | @Test
12 | public void addition_isCorrect() throws Exception {
13 | assertEquals(4, 2 + 2);
14 | }
15 | }
--------------------------------------------------------------------------------
/app/src/test/kotlin/com/agn/v2ray/ExampleUnitTest.kt:
--------------------------------------------------------------------------------
1 | import org.junit.Assert.*
2 | import org.junit.Test
3 | import com.agn.v2ray.util.Utils
4 |
5 | class UtilTest {
6 |
7 | @Test
8 | fun test_parseInt() {
9 | assertEquals(Utils.parseInt("1234"), 1234)
10 | }
11 |
12 | @Test
13 | fun test_isIpAddress() {
14 | assertFalse(Utils.isIpAddress("114.113.112.266"))
15 | assertFalse(Utils.isIpAddress("666.666.666.666"))
16 | assertFalse(Utils.isIpAddress("256.0.0.0" ))
17 | assertFalse(Utils.isIpAddress("::ffff:127.0.0.0.1" ))
18 | assertFalse(Utils.isIpAddress("baidu.com"))
19 | assertFalse(Utils.isIpAddress(""))
20 |
21 | assertTrue(Utils.isIpAddress("127.0.0.1" ))
22 | assertTrue(Utils.isIpAddress("127.0.0.1:80" ))
23 | assertTrue(Utils.isIpAddress("0.0.0.0/0" ))
24 | assertTrue(Utils.isIpAddress("::1" ))
25 | assertTrue(Utils.isIpAddress("[::1]:80" ))
26 | assertTrue(Utils.isIpAddress("2605:2700:0:3::4713:93e3" ))
27 | assertTrue(Utils.isIpAddress("[2605:2700:0:3::4713:93e3]:80" ))
28 | assertTrue(Utils.isIpAddress("::ffff:192.168.173.22" ))
29 | assertTrue(Utils.isIpAddress("[::ffff:192.168.173.22]:80" ))
30 | assertTrue(Utils.isIpAddress("1::" ))
31 | assertTrue(Utils.isIpAddress("::" ))
32 | assertTrue(Utils.isIpAddress("::/0" ))
33 | assertTrue(Utils.isIpAddress("10.24.56.0/24" ))
34 | assertTrue(Utils.isIpAddress("2001:4321::1" ))
35 | assertTrue(Utils.isIpAddress("240e:1234:abcd:12::6666" ))
36 | assertTrue(Utils.isIpAddress("240e:1234:abcd:12::/64" ))
37 | }
38 | }
39 |
40 |
--------------------------------------------------------------------------------
/build.gradle:
--------------------------------------------------------------------------------
1 | // Top-level build file where you can add configuration options common to all sub-projects/modules.
2 |
3 | buildscript {
4 | repositories {
5 | google()
6 | mavenCentral()
7 | maven {
8 | url 'https://maven.google.com/'
9 | name 'Google'
10 |
11 |
12 | }
13 | jcenter()
14 | gradlePluginPortal()
15 | maven { url "https://jitpack.io" }
16 |
17 | }
18 | dependencies {
19 | classpath 'com.android.tools.build:gradle:8.3.0-alpha14'
20 | classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:1.9.20"
21 |
22 | }
23 | }
24 |
25 | allprojects {
26 | repositories {
27 | google()
28 | mavenCentral()
29 | maven {
30 | url 'https://maven.google.com/'
31 | name 'Google'
32 |
33 |
34 | }
35 | jcenter()
36 | gradlePluginPortal()
37 | maven { url "https://jitpack.io" }
38 |
39 | }
40 | }
41 |
42 | task clean(type: Delete) {
43 | delete rootProject.buildDir
44 | }
45 |
--------------------------------------------------------------------------------
/daynightswitch/.gitignore:
--------------------------------------------------------------------------------
1 | /build
2 |
--------------------------------------------------------------------------------
/daynightswitch/build.gradle:
--------------------------------------------------------------------------------
1 | apply plugin: 'com.android.library'
2 | android {
3 | namespace "com.agn.daynightswitch"
4 |
5 | compileSdk 34
6 | defaultConfig {
7 | minSdkVersion 21
8 | targetSdkVersion 34
9 | versionCode 1
10 | versionName "1.0.1"
11 | testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
12 | consumerProguardFiles "consumer-rules.pro"
13 | }
14 |
15 | buildTypes {
16 | release {
17 | minifyEnabled false
18 | proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
19 | }
20 | }
21 | }
22 |
23 | dependencies {
24 | implementation fileTree(dir: 'libs', include: ['*.jar'])
25 | }
--------------------------------------------------------------------------------
/daynightswitch/proguard-rules.pro:
--------------------------------------------------------------------------------
1 | # Add project specific ProGuard rules here.
2 | # By default, the flags in this file are appended to flags specified
3 | # in C:\Android\sdk/tools/proguard/proguard-android.txt
4 | # You can edit the include path and order by changing the proguardFiles
5 | # directive in build.gradle.
6 | #
7 | # For more details, see
8 | # http://developer.android.com/guide/developing/tools/proguard.html
9 |
10 | # Add any project specific keep options here:
11 |
12 | # If your project uses WebView with JS, uncomment the following
13 | # and specify the fully qualified class name to the JavaScript interface
14 | # class:
15 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview {
16 | # public *;
17 | #}
18 |
19 | # Uncomment this to preserve the line number information for
20 | # debugging stack traces.
21 | #-keepattributes SourceFile,LineNumberTable
22 |
23 | # If you keep the line number information, uncomment this to
24 | # hide the original source file name.
25 | #-renamesourcefileattribute SourceFile
26 |
--------------------------------------------------------------------------------
/daynightswitch/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
4 |
5 |
9 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/daynightswitch/src/main/java/com/agn/daynightswitch/DayNightSwitchAnimListener.java:
--------------------------------------------------------------------------------
1 | package com.agn.daynightswitch;
2 |
3 | /**
4 | * Created by VimalCvs on 02/11/2020.
5 | */
6 |
7 | public interface DayNightSwitchAnimListener {
8 |
9 | void onAnimStart();
10 | void onAnimEnd();
11 | void onAnimValueChanged(float value);
12 |
13 | }
14 |
--------------------------------------------------------------------------------
/daynightswitch/src/main/java/com/agn/daynightswitch/DayNightSwitchListener.java:
--------------------------------------------------------------------------------
1 | package com.agn.daynightswitch;
2 |
3 | /**
4 | * Created by VimalCvs on 02/11/2020.
5 | */
6 |
7 | public interface DayNightSwitchListener {
8 | void onSwitch(boolean is_night);
9 | }
10 |
--------------------------------------------------------------------------------
/daynightswitch/src/main/res/drawable-hdpi/dark_background.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/khaledagn/V2rayAGN/f348cb956337c1f9cbcc553f4beb0cf0c9f9bed8/daynightswitch/src/main/res/drawable-hdpi/dark_background.png
--------------------------------------------------------------------------------
/daynightswitch/src/main/res/drawable-hdpi/img_clouds.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/khaledagn/V2rayAGN/f348cb956337c1f9cbcc553f4beb0cf0c9f9bed8/daynightswitch/src/main/res/drawable-hdpi/img_clouds.png
--------------------------------------------------------------------------------
/daynightswitch/src/main/res/drawable-hdpi/img_moon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/khaledagn/V2rayAGN/f348cb956337c1f9cbcc553f4beb0cf0c9f9bed8/daynightswitch/src/main/res/drawable-hdpi/img_moon.png
--------------------------------------------------------------------------------
/daynightswitch/src/main/res/drawable-hdpi/img_sun.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/khaledagn/V2rayAGN/f348cb956337c1f9cbcc553f4beb0cf0c9f9bed8/daynightswitch/src/main/res/drawable-hdpi/img_sun.png
--------------------------------------------------------------------------------
/daynightswitch/src/main/res/drawable-ldpi/dark_background.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/khaledagn/V2rayAGN/f348cb956337c1f9cbcc553f4beb0cf0c9f9bed8/daynightswitch/src/main/res/drawable-ldpi/dark_background.png
--------------------------------------------------------------------------------
/daynightswitch/src/main/res/drawable-ldpi/img_clouds.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/khaledagn/V2rayAGN/f348cb956337c1f9cbcc553f4beb0cf0c9f9bed8/daynightswitch/src/main/res/drawable-ldpi/img_clouds.png
--------------------------------------------------------------------------------
/daynightswitch/src/main/res/drawable-ldpi/img_moon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/khaledagn/V2rayAGN/f348cb956337c1f9cbcc553f4beb0cf0c9f9bed8/daynightswitch/src/main/res/drawable-ldpi/img_moon.png
--------------------------------------------------------------------------------
/daynightswitch/src/main/res/drawable-ldpi/img_sun.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/khaledagn/V2rayAGN/f348cb956337c1f9cbcc553f4beb0cf0c9f9bed8/daynightswitch/src/main/res/drawable-ldpi/img_sun.png
--------------------------------------------------------------------------------
/daynightswitch/src/main/res/drawable-mdpi/dark_background.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/khaledagn/V2rayAGN/f348cb956337c1f9cbcc553f4beb0cf0c9f9bed8/daynightswitch/src/main/res/drawable-mdpi/dark_background.png
--------------------------------------------------------------------------------
/daynightswitch/src/main/res/drawable-mdpi/img_clouds.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/khaledagn/V2rayAGN/f348cb956337c1f9cbcc553f4beb0cf0c9f9bed8/daynightswitch/src/main/res/drawable-mdpi/img_clouds.png
--------------------------------------------------------------------------------
/daynightswitch/src/main/res/drawable-mdpi/img_moon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/khaledagn/V2rayAGN/f348cb956337c1f9cbcc553f4beb0cf0c9f9bed8/daynightswitch/src/main/res/drawable-mdpi/img_moon.png
--------------------------------------------------------------------------------
/daynightswitch/src/main/res/drawable-mdpi/img_sun.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/khaledagn/V2rayAGN/f348cb956337c1f9cbcc553f4beb0cf0c9f9bed8/daynightswitch/src/main/res/drawable-mdpi/img_sun.png
--------------------------------------------------------------------------------
/daynightswitch/src/main/res/drawable-xhdpi/dark_background.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/khaledagn/V2rayAGN/f348cb956337c1f9cbcc553f4beb0cf0c9f9bed8/daynightswitch/src/main/res/drawable-xhdpi/dark_background.png
--------------------------------------------------------------------------------
/daynightswitch/src/main/res/drawable-xhdpi/img_clouds.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/khaledagn/V2rayAGN/f348cb956337c1f9cbcc553f4beb0cf0c9f9bed8/daynightswitch/src/main/res/drawable-xhdpi/img_clouds.png
--------------------------------------------------------------------------------
/daynightswitch/src/main/res/drawable-xhdpi/img_moon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/khaledagn/V2rayAGN/f348cb956337c1f9cbcc553f4beb0cf0c9f9bed8/daynightswitch/src/main/res/drawable-xhdpi/img_moon.png
--------------------------------------------------------------------------------
/daynightswitch/src/main/res/drawable-xhdpi/img_sun.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/khaledagn/V2rayAGN/f348cb956337c1f9cbcc553f4beb0cf0c9f9bed8/daynightswitch/src/main/res/drawable-xhdpi/img_sun.png
--------------------------------------------------------------------------------
/daynightswitch/src/main/res/drawable-xxhdpi/dark_background.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/khaledagn/V2rayAGN/f348cb956337c1f9cbcc553f4beb0cf0c9f9bed8/daynightswitch/src/main/res/drawable-xxhdpi/dark_background.png
--------------------------------------------------------------------------------
/daynightswitch/src/main/res/drawable-xxhdpi/img_clouds.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/khaledagn/V2rayAGN/f348cb956337c1f9cbcc553f4beb0cf0c9f9bed8/daynightswitch/src/main/res/drawable-xxhdpi/img_clouds.png
--------------------------------------------------------------------------------
/daynightswitch/src/main/res/drawable-xxhdpi/img_moon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/khaledagn/V2rayAGN/f348cb956337c1f9cbcc553f4beb0cf0c9f9bed8/daynightswitch/src/main/res/drawable-xxhdpi/img_moon.png
--------------------------------------------------------------------------------
/daynightswitch/src/main/res/drawable-xxhdpi/img_sun.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/khaledagn/V2rayAGN/f348cb956337c1f9cbcc553f4beb0cf0c9f9bed8/daynightswitch/src/main/res/drawable-xxhdpi/img_sun.png
--------------------------------------------------------------------------------
/daynightswitch/src/main/res/drawable-xxxhdpi/dark_background.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/khaledagn/V2rayAGN/f348cb956337c1f9cbcc553f4beb0cf0c9f9bed8/daynightswitch/src/main/res/drawable-xxxhdpi/dark_background.png
--------------------------------------------------------------------------------
/daynightswitch/src/main/res/drawable-xxxhdpi/img_clouds.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/khaledagn/V2rayAGN/f348cb956337c1f9cbcc553f4beb0cf0c9f9bed8/daynightswitch/src/main/res/drawable-xxxhdpi/img_clouds.png
--------------------------------------------------------------------------------
/daynightswitch/src/main/res/drawable-xxxhdpi/img_moon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/khaledagn/V2rayAGN/f348cb956337c1f9cbcc553f4beb0cf0c9f9bed8/daynightswitch/src/main/res/drawable-xxxhdpi/img_moon.png
--------------------------------------------------------------------------------
/daynightswitch/src/main/res/drawable-xxxhdpi/img_sun.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/khaledagn/V2rayAGN/f348cb956337c1f9cbcc553f4beb0cf0c9f9bed8/daynightswitch/src/main/res/drawable-xxxhdpi/img_sun.png
--------------------------------------------------------------------------------
/daynightswitch/src/main/res/values/colors.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | #59ccda
4 | #4D354653
5 |
6 |
--------------------------------------------------------------------------------
/daynightswitch/src/main/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 | DayNightSwitch
3 |
4 |
--------------------------------------------------------------------------------
/gradle.properties:
--------------------------------------------------------------------------------
1 |
2 | buildToolsVer=33.0.2
3 | compileSdkVer=33
4 | targetSdkVer=33
5 | kotlin.incremental=true
6 | android.useAndroidX=true
7 | android.enableJetifier=true
8 | kotlin.code.style=official
9 | android.nonTransitiveRClass=true
10 | org.gradle.jvmargs=-Xmx2048m -XX:MaxPermSize=512m -XX:+HeapDumpOnOutOfMemoryError -Dfile.encoding=UTF-8
11 |
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/khaledagn/V2rayAGN/f348cb956337c1f9cbcc553f4beb0cf0c9f9bed8/gradle/wrapper/gradle-wrapper.jar
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.properties:
--------------------------------------------------------------------------------
1 | #Wed Nov 30 21:35:01 EST 2022
2 | distributionBase=GRADLE_USER_HOME
3 | distributionUrl=https\://services.gradle.org/distributions/gradle-8.4-all.zip
4 | distributionPath=wrapper/dists
5 | zipStorePath=wrapper/dists
6 | zipStoreBase=GRADLE_USER_HOME
7 |
--------------------------------------------------------------------------------
/gradlew.bat:
--------------------------------------------------------------------------------
1 | @if "%DEBUG%" == "" @echo off
2 | @rem ##########################################################################
3 | @rem
4 | @rem Gradle startup script for Windows
5 | @rem
6 | @rem ##########################################################################
7 |
8 | @rem Set local scope for the variables with windows NT shell
9 | if "%OS%"=="Windows_NT" setlocal
10 |
11 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
12 | set DEFAULT_JVM_OPTS=
13 |
14 | set DIRNAME=%~dp0
15 | if "%DIRNAME%" == "" set DIRNAME=.
16 | set APP_BASE_NAME=%~n0
17 | set APP_HOME=%DIRNAME%
18 |
19 | @rem Find java.exe
20 | if defined JAVA_HOME goto findJavaFromJavaHome
21 |
22 | set JAVA_EXE=java.exe
23 | %JAVA_EXE% -version >NUL 2>&1
24 | if "%ERRORLEVEL%" == "0" goto init
25 |
26 | echo.
27 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
28 | echo.
29 | echo Please set the JAVA_HOME variable in your environment to match the
30 | echo location of your Java installation.
31 |
32 | goto fail
33 |
34 | :findJavaFromJavaHome
35 | set JAVA_HOME=%JAVA_HOME:"=%
36 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe
37 |
38 | if exist "%JAVA_EXE%" goto init
39 |
40 | echo.
41 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
42 | echo.
43 | echo Please set the JAVA_HOME variable in your environment to match the
44 | echo location of your Java installation.
45 |
46 | goto fail
47 |
48 | :init
49 | @rem Get command-line arguments, handling Windowz variants
50 |
51 | if not "%OS%" == "Windows_NT" goto win9xME_args
52 | if "%@eval[2+2]" == "4" goto 4NT_args
53 |
54 | :win9xME_args
55 | @rem Slurp the command line arguments.
56 | set CMD_LINE_ARGS=
57 | set _SKIP=2
58 |
59 | :win9xME_args_slurp
60 | if "x%~1" == "x" goto execute
61 |
62 | set CMD_LINE_ARGS=%*
63 | goto execute
64 |
65 | :4NT_args
66 | @rem Get arguments from the 4NT Shell from JP Software
67 | set CMD_LINE_ARGS=%$
68 |
69 | :execute
70 | @rem Setup the command line
71 |
72 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
73 |
74 | @rem Execute Gradle
75 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
76 |
77 | :end
78 | @rem End local scope for the variables with windows NT shell
79 | if "%ERRORLEVEL%"=="0" goto mainEnd
80 |
81 | :fail
82 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
83 | rem the _cmd.exe /c_ return code!
84 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
85 | exit /b 1
86 |
87 | :mainEnd
88 | if "%OS%"=="Windows_NT" endlocal
89 |
90 | :omega
91 |
--------------------------------------------------------------------------------
/settings.gradle:
--------------------------------------------------------------------------------
1 |
2 | include ':app','daynightswitch'
3 |
--------------------------------------------------------------------------------