The response has been limited to 50k tokens of the smallest files in the repo. You can remove this limitation by removing the max tokens filter.
├── .github
    ├── dependabot.yml
    └── workflows
    │   └── release.yaml
├── .gitignore
├── README.md
├── app
    ├── .gitignore
    ├── build.gradle
    ├── lint-baseline.xml
    ├── proguard-rules.pro
    └── src
    │   └── main
    │       ├── AndroidManifest.xml
    │       ├── ic_launcher-playstore.png
    │       ├── java
    │           └── org
    │           │   └── bepass
    │           │       └── oblivion
    │           │           ├── BypassListAppsAdapter.java
    │           │           ├── EditSheet.java
    │           │           ├── EndpointsBottomSheet.java
    │           │           ├── SplitTunnelOptionsAdapter.java
    │           │           ├── base
    │           │               ├── ApplicationLoader.java
    │           │               ├── BaseActivity.java
    │           │               └── StateAwareBaseActivity.java
    │           │           ├── component
    │           │               ├── Icon.java
    │           │               └── TouchAwareSwitch.java
    │           │           ├── enums
    │           │               ├── ConnectionState.java
    │           │               └── SplitTunnelMode.java
    │           │           ├── interfaces
    │           │               ├── ConnectionStateChangeListener.java
    │           │               └── SheetsCallBack.java
    │           │           ├── model
    │           │               └── IPDetails.java
    │           │           ├── service
    │           │               ├── OblivionVpnService.java
    │           │               └── QuickStartService.java
    │           │           ├── ui
    │           │               ├── InfoActivity.java
    │           │               ├── LogActivity.java
    │           │               ├── MainActivity.java
    │           │               ├── SettingsActivity.java
    │           │               ├── SplashScreenActivity.java
    │           │               └── SplitTunnelActivity.java
    │           │           └── utils
    │           │               ├── BatteryOptimization.kt
    │           │               ├── ColorUtils.java
    │           │               ├── CountryCodeExtensions.kt
    │           │               ├── CountryUtils.java
    │           │               ├── FileManager.java
    │           │               ├── ISPUtils.kt
    │           │               ├── LocaleHandler.java
    │           │               ├── LocaleHelper.java
    │           │               ├── NetworkUtils.java
    │           │               ├── PublicIPUtils.java
    │           │               ├── SystemUtils.java
    │           │               └── ThemeHelper.java
    │       └── res
    │           ├── color
    │               ├── checkbox_tint.xml
    │               └── tint_selector.xml
    │           ├── drawable-anydpi
    │               ├── about_item.xml
    │               ├── bottom_sheet_closer.xml
    │               ├── edittext_back.xml
    │               ├── ic_back.xml
    │               ├── ic_bug.xml
    │               ├── ic_info.xml
    │               ├── ic_power.xml
    │               └── ic_settings.xml
    │           ├── drawable-hdpi
    │               ├── ic_back.png
    │               ├── ic_bug.png
    │               ├── ic_github.png
    │               ├── ic_info.png
    │               ├── ic_settings.png
    │               ├── ic_translate.png
    │               └── rounded_bottom_sheet.xml
    │           ├── drawable-mdpi
    │               ├── ic_back.png
    │               ├── ic_bug.png
    │               ├── ic_github.png
    │               ├── ic_info.png
    │               ├── ic_ircf.png
    │               ├── ic_power.png
    │               ├── ic_settings.png
    │               ├── ic_translate.png
    │               └── ic_twitter.png
    │           ├── drawable-xhdpi
    │               ├── ic_back.png
    │               ├── ic_bug.png
    │               ├── ic_github.png
    │               ├── ic_info.png
    │               ├── ic_ircf.png
    │               ├── ic_power.png
    │               ├── ic_settings.png
    │               ├── ic_translate.png
    │               └── ic_twitter.png
    │           ├── drawable-xxhdpi
    │               ├── ic_back.png
    │               ├── ic_bug.png
    │               ├── ic_github.png
    │               ├── ic_info.png
    │               ├── ic_ircf.png
    │               ├── ic_power.png
    │               ├── ic_settings.png
    │               ├── ic_translate.png
    │               └── ic_twitter.png
    │           ├── drawable-xxxhdpi
    │               ├── ic_github.png
    │               ├── ic_ircf.png
    │               ├── ic_translate.png
    │               └── ic_twitter.png
    │           ├── drawable
    │               ├── background_gradient.xml
    │               ├── bottom_sheet_cancel.xml
    │               ├── button.xml
    │               ├── button_op.xml
    │               ├── check.xml
    │               ├── custom_progress_drawable.xml
    │               ├── endpoint_sheet.xml
    │               ├── expand_up.xml
    │               ├── light_shadow_bottom.xml
    │               ├── segaro.png
    │               ├── switch_ripple.xml
    │               ├── toast_background.xml
    │               ├── vpn_off.xml
    │               ├── vpn_on.xml
    │               └── yousef.png
    │           ├── font
    │               ├── emoji.ttf
    │               ├── oxygenbold.ttf
    │               ├── oxygenlight.ttf
    │               ├── oxygenregular.ttf
    │               ├── shabnam.ttf
    │               ├── shabnambold.ttf
    │               ├── shabnamlight.ttf
    │               ├── shabnammedium.ttf
    │               └── shabnamthin.ttf
    │           ├── layout
    │               ├── activity_info.xml
    │               ├── activity_log.xml
    │               ├── activity_main.xml
    │               ├── activity_settings.xml
    │               ├── activity_splash_screen.xml
    │               ├── activity_split_tunnel.xml
    │               ├── bottom_sheet_endpoints.xml
    │               ├── country_item_layout.xml
    │               ├── dialog_battery_optimization.xml
    │               ├── edit_sheet.xml
    │               ├── installed_app_item.xml
    │               ├── item_endpoint.xml
    │               ├── split_tunnel_options.xml
    │               └── toast.xml
    │           ├── mipmap-anydpi-v26
    │               ├── ic_launcher.xml
    │               └── ic_launcher_round.xml
    │           ├── mipmap-hdpi
    │               ├── ic_launcher.webp
    │               ├── ic_launcher_foreground.webp
    │               ├── ic_launcher_round.webp
    │               └── ic_notification.png
    │           ├── mipmap-mdpi
    │               ├── ic_launcher.webp
    │               ├── ic_launcher_foreground.webp
    │               ├── ic_launcher_round.webp
    │               └── ic_notification.png
    │           ├── mipmap-xhdpi
    │               ├── ic_launcher.webp
    │               ├── ic_launcher_foreground.webp
    │               ├── ic_launcher_round.webp
    │               ├── ic_notification.png
    │               └── tv_banner.png
    │           ├── mipmap-xxhdpi
    │               ├── ic_launcher.webp
    │               ├── ic_launcher_foreground.webp
    │               ├── ic_launcher_round.webp
    │               └── ic_notification.png
    │           ├── mipmap-xxxhdpi
    │               ├── ic_launcher.webp
    │               ├── ic_launcher_foreground.webp
    │               ├── ic_launcher_round.webp
    │               └── ic_notification.png
    │           ├── resources.properties
    │           ├── values-fa
    │               └── strings.xml
    │           ├── values-night
    │               └── colors.xml
    │           ├── values-ru
    │               └── strings.xml
    │           ├── values-tr
    │               └── strings.xml
    │           ├── values-zh
    │               └── strings.xml
    │           ├── values
    │               ├── attrs.xml
    │               ├── colors.xml
    │               ├── ic_launcher_background.xml
    │               ├── strings.xml
    │               ├── styles.xml
    │               └── themes.xml
    │           └── xml
    │               ├── backup_rules.xml
    │               ├── data_extraction_rules.xml
    │               └── network_security_config.xml
├── build.gradle
├── devshell.nix
├── flake.lock
├── flake.nix
├── gradle.properties
├── gradle
    └── wrapper
    │   ├── gradle-wrapper.jar
    │   └── gradle-wrapper.properties
├── gradlew
├── gradlew.bat
├── media
    └── oblivion3.jpg
├── settings.gradle
└── tun2socks
    ├── README.md
    ├── go.mod
    ├── go.sum
    ├── lwip
        └── lwip.go
    ├── tools.go
    └── tun2socks.go


/.github/dependabot.yml:
--------------------------------------------------------------------------------
1 | version: 2
2 | updates:
3 |   - package-ecosystem: "github-actions"
4 |     directory: "/"
5 |     schedule:
6 |       interval: "weekly"
7 | 


--------------------------------------------------------------------------------
/.github/workflows/release.yaml:
--------------------------------------------------------------------------------
 1 | name: Android CI
 2 | 
 3 | on:
 4 |   workflow_dispatch:
 5 |   push:
 6 |     branches: ["main"]
 7 |   release:
 8 |     types: ["published"]
 9 | 
10 | jobs:
11 |   build:
12 |     permissions:
13 |       contents: write
14 | 
15 |     runs-on: ubuntu-latest
16 | 
17 |     env:
18 |       CGO_ENABLED: 0
19 | 
20 |     steps:
21 |       - name: Checkout codebase
22 |         uses: actions/checkout@v4
23 | 
24 |       - name: Set up Go
25 |         uses: actions/setup-go@v5
26 |         with:
27 |           go-version: "1.22"
28 |           check-latest: true
29 | 
30 |       # Set up JDK
31 |       - name: Set Up JDK
32 |         uses: actions/setup-java@v4
33 |         with:
34 |           java-version: "17"
35 |           distribution: "zulu"
36 |           cache: "gradle"
37 | 
38 |       - name: Install NDK
39 |         uses: nttld/setup-ndk@v1
40 |         with:
41 |           ndk-version: r26b
42 |           link-to-sdk: true
43 | 
44 |       - name: Change wrapper permissions
45 |         run: chmod +x ./gradlew
46 | 
47 |       - name: Build Tun2Socks AAR
48 |         run: ./gradlew buildTun2SocksAar
49 | 
50 |       # Run Build Project
51 |       - name: Build gradle project
52 |         run: ./gradlew build
53 | 
54 |       # Build APKs
55 |       - name: Build Release APK
56 |         run: ./gradlew assembleRelease
57 | 
58 |       # Upload build aar to Artifacts
59 |       - name: Upload build aar to Artifacts
60 |         uses: actions/upload-artifact@v4
61 |         with:
62 |           name: "tun2socks"
63 |           path: app/libs/tun2socks.aar
64 | 
65 |       # Upload APK artifact
66 |       - name: Upload files to Artifacts
67 |         uses: actions/upload-artifact@v4
68 |         with:
69 |           name: oblivion-${{ github.sha }}-unsigned.apk
70 |           path: |
71 |             app/build/outputs/apk/release/*.apk


--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
 1 | *.iml
 2 | .gradle
 3 | /local.properties
 4 | /.idea/caches
 5 | /.idea/libraries
 6 | /.idea/modules.xml
 7 | /.idea/workspace.xml
 8 | /.idea/navEditor.xml
 9 | /.idea/assetWizardSettings.xml
10 | .DS_Store
11 | /build
12 | /captures
13 | .externalNativeBuild
14 | .cxx
15 | local.properties
16 | .idea
17 | /app/libs/*.aar
18 | /app/libs/*.jar
19 | /app/libs/.idea
20 | /app/release
21 | 


--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
 1 | # Oblivion - Unofficial Warp Client for Android
 2 | 
 3 | "Internet, for all or none!"
 4 | 
 5 | Oblivion provides secure, optimized internet access through a user-friendly Android app using cloudflare warp technology
 6 | 
 7 | It's leveraging `bepass-sdk` and a custom Go implementation of WireGuard, it's designed for fast and private online experiences.
 8 | 
 9 | ![oblivion3.jpg](media/oblivion3.jpg)
10 | 
11 | ## Features
12 | 
13 | - **Secure VPN**: Custom WireGuard implementation in Go.
14 | - **Optimized Speeds**: Enhanced with `bepass-sdk` for minimal latency.
15 | - **User-Friendly**: Simple, intuitive interface.
16 | 
17 | ## Quick Start
18 | 
19 | 1. **Download**: Grab the APK from our [Releases](https://github.com/bepass-org/oblivion/releases) page or [Google play store](https://play.google.com/store/apps/details?id=org.bepass.oblivion) and install it.
20 |    <a href="https://play.google.com/store/apps/details?id=org.bepass.oblivion">
21 |    <img alt="Get it on Google Play" src="https://play.google.com/intl/en_us/badges/images/generic/en_badge_web_generic.png" width="165" height="64" />
22 |    </a>
23 | 
24 | 2. **Connect**: Launch Oblivion and hit the switch button.
25 | 
26 | ## Building the Project
27 | 
28 | ### Prerequisites
29 | - NDK r26b (26.1.10909125)
30 | - Go 1.22
31 | 
32 | ### Follow the steps below to build the Oblivion:
33 | - In Android Studio, navigate to "Build" in the menu bar.
34 | - Select "Generate Signed Bundle/APK..."
35 | - Choose "APK" and proceed.
36 | 
37 | ## Get Involved
38 | 
39 | We're a community-driven project, aiming to make the internet accessible for all. Whether you want to contribute code, suggest features, or need some help, we'd love to hear from you! Check out our [GitHub Issues](https://github.com/bepass-org/oblivion/issues) or submit a pull request.
40 | 
41 | ## Acknowledgements and Credits
42 | 
43 | This project makes use of several open-source tools and libraries, and we are grateful to the developers and communities behind these projects. In particular, we would like to acknowledge:
44 | 
45 | ### Cloudflare Warp
46 | 
47 | - **Project**: Cloudflare Warp
48 | - **Website**: [Cloudflare Warp](https://www.cloudflare.com/products/warp/)
49 | - **License**: [License information](https://www.cloudflare.com/application/terms/)
50 | - **Description**: Cloudflare Warp is a technology that enhances the security and performance of Internet applications. We use it in our project for its efficient and secure network traffic routing capabilities.
51 | 
52 | ### WireGuard-go
53 | 
54 | - **Project**: WireGuard-go
55 | - **GitHub Repository**: [WireGuard-go on GitHub](https://github.com/WireGuard/wireguard-go)
56 | - **License**: [GNU General Public License v2.0](https://github.com/WireGuard/wireguard-go/blob/master/COPYING)
57 | - **Description**: WireGuard-go is an implementation of the WireGuard secure network tunnel. It's used in our project to provide fast, modern, and secure VPN tunneling.
58 | 
59 | Please note that the use of these tools is governed by their respective licenses, and you should consult those licenses for terms and conditions of use.
60 | 
61 | ## License
62 | 
63 | This project is licensed under the Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International License - see the [CC BY-NC-SA 4.0 License](https://creativecommons.org/licenses/by-nc-sa/4.0/) for details.
64 | 
65 | ### Summary of License
66 | 
67 | The CC BY-NC-SA 4.0 License is a free, copyleft license suitable for non-commercial use. Here's what it means for using this project:
68 | 
69 | - **Attribution (BY)**: You must give appropriate credit, provide a link to the license, and indicate if changes were made. You may do so in any reasonable manner, but not in any way that suggests the licensor endorses you or your use.
70 | 
71 | - **NonCommercial (NC)**: You may not use the material for commercial purposes.
72 | 
73 | - **ShareAlike (SA)**: If you remix, transform, or build upon the material, you must distribute your contributions under the same license as the original.
74 | 
75 | This summary is only a brief overview. For the full legal text, please visit the provided link.
76 | 


--------------------------------------------------------------------------------
/app/.gitignore:
--------------------------------------------------------------------------------
1 | /build


--------------------------------------------------------------------------------
/app/build.gradle:
--------------------------------------------------------------------------------
  1 | plugins {
  2 |     id 'com.android.application'
  3 |     id 'org.jetbrains.kotlin.android'
  4 | }
  5 | 
  6 | android {
  7 |     namespace 'org.bepass.oblivion'
  8 |     compileSdk 34
  9 |     defaultConfig {
 10 |         applicationId "org.bepass.oblivion"
 11 |         minSdk 23 // least supported api level => android 6.0
 12 |         targetSdk 34
 13 |         versionCode 18
 14 |         versionName "8"
 15 | 
 16 |         testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
 17 |         vectorDrawables {
 18 |             useSupportLibrary true
 19 |         }
 20 |     }
 21 |     androidResources {
 22 |         generateLocaleConfig true
 23 |     }
 24 |     buildFeatures {
 25 |         dataBinding = true
 26 |     }
 27 | 
 28 |     buildTypes {
 29 |         release {
 30 |             minifyEnabled true
 31 |             shrinkResources true
 32 |             proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
 33 |         }
 34 |     }
 35 |     compileOptions {
 36 |         sourceCompatibility JavaVersion.VERSION_1_8
 37 |         targetCompatibility JavaVersion.VERSION_1_8
 38 |     }
 39 |     kotlinOptions {
 40 |         jvmTarget = '1.8'
 41 |     }
 42 |     packagingOptions {
 43 |         resources.excludes.add("META-INF/*")
 44 |     }
 45 |     lint {
 46 |         baseline = file("lint-baseline.xml")
 47 |     }
 48 | }
 49 | 
 50 | configurations {
 51 |     configureEach {
 52 |         exclude group: 'org.json', module: 'json'
 53 |     }
 54 | }
 55 | 
 56 | dependencies {
 57 |     implementation 'androidx.appcompat:appcompat:1.7.0'
 58 |     implementation 'com.google.android.material:material:1.12.0'
 59 |     implementation 'androidx.constraintlayout:constraintlayout:2.1.4'
 60 |     implementation 'com.github.zcweng:switch-button:0.0.3@aar'
 61 |     implementation 'androidx.recyclerview:recyclerview:1.3.2'
 62 |     implementation 'com.github.bumptech.glide:glide:4.16.0'
 63 |     implementation 'com.squareup.okhttp3:okhttp:4.12.0'
 64 |     implementation 'com.github.erfansn:locale-config-x:1.0.1'
 65 |     implementation 'com.tencent:mmkv:1.3.14' // we version 1.3.* to support 32-bit
 66 |     implementation fileTree(dir: 'libs', include: ['*.aar', '*.jar'])
 67 | }
 68 | 
 69 | static def findGoExecutable() {
 70 |     def goPath = ["which", "go"].execute().text.trim()
 71 |     if (!goPath || !new File(goPath).exists()) {
 72 |         throw new GradleException("Go executable not found in PATH.")
 73 |     }
 74 |     return goPath
 75 | }
 76 | 
 77 | static def findGomobileExecutable(goExec) {
 78 |     def gomobilePath = ["which", "gomobile"].execute().text.trim()
 79 |     if (gomobilePath && new File(gomobilePath).exists()) {
 80 |         return gomobilePath
 81 |     }
 82 | 
 83 |     // fallback to GOPATH/bin/gomobile (usually ~/go/bin/gomobile)
 84 |     def fallback = "${System.getProperty("user.home")}/go/bin/gomobile"
 85 |     if (new File(fallback).exists()) {
 86 |         return fallback
 87 |     }
 88 | 
 89 |     // try to install
 90 |     println "Installing gomobile..."
 91 |     def install = ["sh", "-c", "$goExec install golang.org/x/mobile/cmd/gomobile@latest"].execute()
 92 |     install.waitForProcessOutput(System.out, System.err)
 93 |     if (install.exitValue() != 0 || !new File(fallback).exists()) {
 94 |         throw new GradleException("Failed to install gomobile")
 95 |     }
 96 |     return fallback
 97 | }
 98 | 
 99 | def goExec = findGoExecutable()
100 | def gomobileExec = findGomobileExecutable(goExec)
101 | 
102 | tasks.register("preBuildTun2SocksAar", Exec) {
103 |     workingDir "../tun2socks"
104 |     commandLine gomobileExec, "init"
105 | }
106 | 
107 | tasks.register("buildTun2SocksAar", Exec) {
108 |     doFirst {
109 |         File myDir = new File("$projectDir/libs")
110 |         if (!myDir.exists()) {
111 |             myDir.mkdirs()
112 |         }
113 |     }
114 | 
115 |     workingDir "../tun2socks"
116 |     commandLine gomobileExec, "bind",
117 |             "-ldflags=-w -s",
118 |             "-target=android",
119 |             "-androidapi=$android.defaultConfig.minSdk",
120 |             "-o=$projectDir/libs/tun2socks.aar", "."
121 | 
122 |     dependsOn(preBuildTun2SocksAar)
123 | }
124 | 
125 | preBuild.dependsOn(buildTun2SocksAar)


--------------------------------------------------------------------------------
/app/lint-baseline.xml:
--------------------------------------------------------------------------------
 1 | <?xml version="1.0" encoding="UTF-8"?>
 2 | <issues format="6" by="lint 8.1.2" type="baseline" client="gradle" dependencies="false" name="AGP (8.1.2)" variant="fatal" version="8.1.2">
 3 | 
 4 |     <issue
 5 |         id="DuplicatePlatformClasses"
 6 |         message="`json` defines classes that conflict with classes now provided by Android. Solutions include finding newer versions or alternative libraries that don&apos;t have the same problem (for example, for `httpclient` use `HttpUrlConnection` or `okhttp` instead), or repackaging the library using something like `jarjar`.">
 7 |         <location
 8 |             file="build.gradle"/>
 9 |     </issue>
10 | 
11 | </issues>
12 | 


--------------------------------------------------------------------------------
/app/proguard-rules.pro:
--------------------------------------------------------------------------------
 1 | # Add project specific ProGuard rules here.
 2 | # You can control the set of applied configuration files using the
 3 | # proguardFiles setting in build.gradle.
 4 | #
 5 | # For more details, see
 6 | #   http://developer.android.com/guide/developing/tools/proguard.html
 7 | 
 8 | # If your project uses WebView with JS, uncomment the following
 9 | # and specify the fully qualified class name to the JavaScript interface
10 | # class:
11 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview {
12 | #   public *;
13 | #}
14 | 
15 | # Uncomment this to preserve the line number information for
16 | # debugging stack traces.
17 | #-keepattributes SourceFile,LineNumberTable
18 | 
19 | # If you keep the line number information, uncomment this to
20 | # hide the original source file name.
21 | #-renamesourcefileattribute SourceFile
22 | 


--------------------------------------------------------------------------------
/app/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
  1 | <?xml version="1.0" encoding="utf-8"?>
  2 | <manifest xmlns:android="http://schemas.android.com/apk/res/android"
  3 |     xmlns:tools="http://schemas.android.com/tools">
  4 | 
  5 |     <uses-feature android:name="android.hardware.touchscreen" android:required="false" />
  6 |     <uses-feature android:name="android.software.leanback" android:required="false" />
  7 | 
  8 |     <uses-permission android:name="android.permission.INTERNET" />
  9 |     <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
 10 |     <uses-permission android:name="android.permission.ACCESS_WIFI_STATE"/>
 11 |     <uses-feature android:name="android.hardware.wifi" android:required="false" />
 12 |     <uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
 13 |     <uses-permission android:name="android.permission.POST_NOTIFICATIONS" />
 14 |     <uses-permission android:name="android.permission.WAKE_LOCK" />
 15 |     <uses-permission android:name="android.permission.FOREGROUND_SERVICE_SYSTEM_EXEMPTED"/>
 16 |     <uses-permission android:name="android.permission.REQUEST_IGNORE_BATTERY_OPTIMIZATIONS"/>
 17 |     <uses-permission android:name="android.permission.SCHEDULE_EXACT_ALARM" />
 18 |     <queries>
 19 |         <intent>
 20 |             <action android:name="android.intent.action.MAIN" />
 21 |         </intent>
 22 |     </queries>
 23 | 
 24 |     <application
 25 |         android:allowBackup="true"
 26 |         android:dataExtractionRules="@xml/data_extraction_rules"
 27 |         android:fullBackupContent="@xml/backup_rules"
 28 |         android:icon="@mipmap/ic_launcher"
 29 |         android:label="@string/app_name"
 30 |         android:banner="@mipmap/tv_banner"
 31 |         android:roundIcon="@mipmap/ic_launcher_round"
 32 |         android:supportsRtl="true"
 33 |         android:name=".base.ApplicationLoader"
 34 |         tools:replace="android:supportsRtl"
 35 |         android:screenOrientation="portrait"
 36 |         android:enableOnBackInvokedCallback="true"
 37 |         android:theme="@style/Theme.OblivionUI"
 38 |         android:networkSecurityConfig="@xml/network_security_config"
 39 |         tools:targetApi="tiramisu"
 40 |         tools:ignore="DiscouragedApi">
 41 | 
 42 |         <service
 43 |             android:name=".service.OblivionVpnService"
 44 |             android:enabled="true"
 45 |             android:exported="true"
 46 |             android:permission="android.permission.BIND_VPN_SERVICE"
 47 |             android:foregroundServiceType="systemExempted"
 48 |             android:process=":vpn_background">
 49 |             <intent-filter>
 50 |                 <action android:name="android.net.VpnService" />
 51 |                 <action android:name="android.net.conn.CONNECTIVITY_CHANGE"/>
 52 |             </intent-filter>
 53 | 
 54 |             <meta-data
 55 |                 android:name="android.net.VpnService.SUPPORTS_ALWAYS_ON"
 56 |                 android:value="true" />
 57 |         </service>
 58 | 
 59 |         <service
 60 |             android:name=".service.QuickStartService"
 61 |             android:exported="true"
 62 |             android:label="Oblivion"
 63 |             android:icon="@drawable/vpn_off"
 64 |             android:permission="android.permission.BIND_QUICK_SETTINGS_TILE">
 65 |             <meta-data android:name="android.service.quicksettings.TOGGLEABLE_TILE"
 66 |                 android:value="true" />
 67 |             <intent-filter>
 68 |                 <action android:name="android.service.quicksettings.action.QS_TILE" />
 69 |             </intent-filter>
 70 | 
 71 |     </service>
 72 | 
 73 |         <service
 74 |             android:name="androidx.appcompat.app.AppLocalesMetadataHolderService"
 75 |             android:enabled="false"
 76 |             android:exported="false">
 77 |             <meta-data
 78 |                 android:name="autoStoreLocales"
 79 |                 android:value="true" />
 80 |         </service>
 81 | 
 82 |         <activity android:name="org.bepass.oblivion.ui.SplashScreenActivity"
 83 |             android:exported="true">
 84 |             <intent-filter>
 85 |                 <action android:name="android.intent.action.MAIN" />
 86 |                 <category android:name="android.intent.category.LAUNCHER" />
 87 |                 <category android:name="android.intent.category.LEANBACK_LAUNCHER" />
 88 |             </intent-filter>
 89 |         </activity>
 90 |         <activity
 91 |             android:name="org.bepass.oblivion.ui.MainActivity"
 92 |             android:exported="true"
 93 |             android:theme="@style/Theme.OblivionUI">
 94 |             <intent-filter>
 95 |                 <action android:name="android.intent.action.MAIN" />
 96 |                 <action android:name="android.service.quicksettings.action.QS_TILE_PREFERENCES" />
 97 |             </intent-filter>
 98 |         </activity>
 99 |         <activity
100 |             android:name="org.bepass.oblivion.ui.InfoActivity"
101 |             android:exported="false" />
102 |         <activity
103 |             android:name="org.bepass.oblivion.ui.LogActivity"
104 |             android:exported="false" />
105 |         <activity
106 |             android:name="org.bepass.oblivion.ui.SettingsActivity"
107 |             android:exported="false"
108 |             android:windowSoftInputMode="adjustResize" />
109 | 
110 |         <activity
111 |             android:name=".ui.SplitTunnelActivity"
112 |             android:exported="false" />
113 |     </application>
114 | 
115 | </manifest>
116 | 


--------------------------------------------------------------------------------
/app/src/main/ic_launcher-playstore.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bepass-org/oblivion/2ed61afd06003949a59f0bfec7281cfb80814e1e/app/src/main/ic_launcher-playstore.png


--------------------------------------------------------------------------------
/app/src/main/java/org/bepass/oblivion/BypassListAppsAdapter.java:
--------------------------------------------------------------------------------
  1 | package org.bepass.oblivion;
  2 | 
  3 | import android.annotation.SuppressLint;
  4 | import android.content.Context;
  5 | import android.content.pm.ApplicationInfo;
  6 | import android.content.pm.PackageManager;
  7 | import android.graphics.drawable.Drawable;
  8 | import android.os.Handler;
  9 | import android.os.Looper;
 10 | import android.view.LayoutInflater;
 11 | import android.view.View;
 12 | import android.view.ViewGroup;
 13 | import android.widget.CheckBox;
 14 | import android.widget.TextView;
 15 | 
 16 | import androidx.annotation.NonNull;
 17 | import androidx.recyclerview.widget.RecyclerView;
 18 | 
 19 | import com.bumptech.glide.Glide;
 20 | import com.google.android.material.imageview.ShapeableImageView;
 21 | 
 22 | import org.bepass.oblivion.utils.FileManager;
 23 | 
 24 | import java.util.ArrayList;
 25 | import java.util.HashSet;
 26 | import java.util.List;
 27 | import java.util.Set;
 28 | import java.util.concurrent.ExecutorService;
 29 | import java.util.concurrent.Executors;
 30 | 
 31 | public class BypassListAppsAdapter extends RecyclerView.Adapter<BypassListAppsAdapter.ViewHolder> {
 32 | 
 33 |     private final ExecutorService executor = Executors.newSingleThreadExecutor();
 34 |     private final Handler handler = new Handler(Looper.getMainLooper());
 35 |     private final LoadListener loadListener;
 36 |     private List<AppInfo> appList = new ArrayList<>();
 37 |     private OnAppSelectListener onAppSelectListener;
 38 | 
 39 |     public BypassListAppsAdapter(Context context, LoadListener loadListener) {
 40 |         this.loadListener = loadListener;
 41 |         loadApps(context, false);
 42 |     }
 43 | 
 44 |     private void loadApps(Context context, boolean shouldShowSystemApps) {
 45 |         if (loadListener != null) loadListener.onLoad(true);
 46 |         executor.submit(() -> {
 47 |             appList = getInstalledApps(context, shouldShowSystemApps);
 48 |             handler.post(() -> {
 49 |                 notifyDataSetChanged();
 50 |                 if (loadListener != null) loadListener.onLoad(false);
 51 |             });
 52 |         });
 53 |     }
 54 | 
 55 |     private List<AppInfo> getInstalledApps(Context context, boolean shouldShowSystemApps) {
 56 |         Set<String> selectedApps = FileManager.getStringSet("splitTunnelApps", new HashSet<>());
 57 |         PackageManager packageManager = context.getPackageManager();
 58 |         @SuppressLint("QueryPermissionsNeeded") List<ApplicationInfo> packages = packageManager.getInstalledApplications(PackageManager.GET_META_DATA);
 59 |         List<AppInfo> appList = new ArrayList<>(packages.size());
 60 | 
 61 |         for (ApplicationInfo packageInfo : packages) {
 62 |             if (!shouldShowSystemApps && (packageInfo.flags & ApplicationInfo.FLAG_SYSTEM) != 0) continue;
 63 |             if (packageInfo.packageName.equals(context.getPackageName())) continue;
 64 | 
 65 |             appList.add(new AppInfo(
 66 |                     packageInfo.loadLabel(packageManager).toString(),
 67 |                     () -> packageInfo.loadIcon(packageManager),
 68 |                     packageInfo.packageName,
 69 |                     selectedApps.contains(packageInfo.packageName)
 70 |             ));
 71 |         }
 72 |         return appList;
 73 |     }
 74 | 
 75 |     public void setShouldShowSystemApps(Context context, boolean shouldShowSystemApps) {
 76 |         loadApps(context, shouldShowSystemApps);
 77 |     }
 78 | 
 79 |     public void setOnAppSelectListener(OnAppSelectListener onAppSelectListener) {
 80 |         this.onAppSelectListener = onAppSelectListener;
 81 |     }
 82 | 
 83 |     @NonNull
 84 |     @Override
 85 |     public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
 86 |         View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.installed_app_item, parent, false);
 87 |         return new ViewHolder(view);
 88 |     }
 89 | 
 90 |     @Override
 91 |     public void onBindViewHolder(@NonNull ViewHolder holder, int position) {
 92 |         AppInfo appInfo = appList.get(position);
 93 |         holder.appNameTextView.setText(appInfo.appName);
 94 |         holder.checkBox.setChecked(appInfo.isSelected);
 95 |         Glide.with(holder.itemView).load(appInfo.iconLoader.load()).into(holder.icon);
 96 | 
 97 |         holder.itemView.setOnClickListener(v -> {
 98 |             appInfo.isSelected = !appInfo.isSelected;
 99 |             notifyItemChanged(position);
100 | 
101 |             Set<String> newSet = new HashSet<>(FileManager.getStringSet("splitTunnelApps", new HashSet<>()));
102 |             if (appInfo.isSelected) {
103 |                 newSet.add(appInfo.packageName);
104 |             } else {
105 |                 newSet.remove(appInfo.packageName);
106 |             }
107 |             FileManager.set("splitTunnelApps", newSet);
108 | 
109 |             if (onAppSelectListener != null)
110 |                 onAppSelectListener.onSelect(appInfo.packageName, appInfo.isSelected);
111 |         });
112 |     }
113 | 
114 |     @Override
115 |     public int getItemCount() {
116 |         return appList.size();
117 |     }
118 | 
119 |     public interface LoadListener {
120 |         void onLoad(boolean loading);
121 |     }
122 | 
123 |     public interface OnAppSelectListener {
124 |         void onSelect(String packageName, boolean selected);
125 |     }
126 | 
127 |     public static class ViewHolder extends RecyclerView.ViewHolder {
128 |         TextView appNameTextView;
129 |         CheckBox checkBox;
130 |         ShapeableImageView icon;
131 | 
132 |         public ViewHolder(@NonNull View itemView) {
133 |             super(itemView);
134 |             appNameTextView = itemView.findViewById(R.id.appNameTextView);
135 |             checkBox = itemView.findViewById(R.id.checkBox);
136 |             icon = itemView.findViewById(R.id.icon);
137 |         }
138 |     }
139 | 
140 |     public static class AppInfo {
141 |         String appName;
142 |         String packageName;
143 |         IconLoader iconLoader;
144 |         boolean isSelected;
145 | 
146 |         AppInfo(String appName, IconLoader iconLoader, String packageName, boolean isSelected) {
147 |             this.appName = appName;
148 |             this.packageName = packageName;
149 |             this.iconLoader = iconLoader;
150 |             this.isSelected = isSelected;
151 |         }
152 | 
153 |         interface IconLoader {
154 |             Drawable load();
155 |         }
156 |     }
157 | }
158 | 


--------------------------------------------------------------------------------
/app/src/main/java/org/bepass/oblivion/EditSheet.java:
--------------------------------------------------------------------------------
 1 | package org.bepass.oblivion;
 2 | 
 3 | import android.content.Context;
 4 | import android.widget.Button;
 5 | import android.widget.EditText;
 6 | import android.widget.TextView;
 7 | 
 8 | import com.google.android.material.bottomsheet.BottomSheetDialog;
 9 | 
10 | import org.bepass.oblivion.interfaces.SheetsCallBack;
11 | import org.bepass.oblivion.utils.FileManager;
12 | 
13 | public class EditSheet {
14 | 
15 |     FileManager fileManager;
16 | 
17 |     Context context;
18 |     BottomSheetDialog sheet;
19 | 
20 |     String title;
21 |     String sharedPrefKey;
22 | 
23 |     TextView titleView;
24 |     EditText value;
25 |     Button apply, cancel;
26 | 
27 |     SheetsCallBack sheetsCallBack;
28 | 
29 |     public EditSheet(Context context, String title, String sharedPrefKey, SheetsCallBack sheetsCallBack) {
30 |         this.context = context;
31 | 
32 |         this.title = context.getString(R.string.editSheetEndpoint).replace("Endpoint",title);
33 |         this.sharedPrefKey = sharedPrefKey;
34 | 
35 |         this.sheetsCallBack = sheetsCallBack;
36 | 
37 |         init();
38 |     }
39 | 
40 | 
41 |     private void init() {
42 |         // Initialize
43 |         sheet = new BottomSheetDialog(context);
44 |         sheet.setContentView(R.layout.edit_sheet);
45 | 
46 |         titleView = sheet.findViewById(R.id.title);
47 |         value = sheet.findViewById(R.id.edittext);
48 | 
49 |         apply = sheet.findViewById(R.id.applyButton);
50 |         cancel = sheet.findViewById(R.id.cancelButton);
51 |     }
52 | 
53 |     public boolean isElementsNull() {
54 |         return titleView == null || value == null || apply == null || cancel == null;
55 |     }
56 | 
57 |     public void start() {
58 |         if (isElementsNull()) {
59 |             return;
60 |         }
61 | 
62 |         titleView.setText(title);
63 |         value.setText(FileManager.getString("USERSETTING_" + sharedPrefKey));
64 | 
65 |         cancel.setOnClickListener(v -> sheet.cancel());
66 |         apply.setOnClickListener(v -> {
67 |             FileManager.set("USERSETTING_" + sharedPrefKey, value.getText().toString());
68 |             sheet.cancel();
69 |         });
70 | 
71 |         sheet.show();
72 |         value.requestFocus();
73 |         sheet.setOnCancelListener(dialog -> sheetsCallBack.onSheetClosed());
74 |     }
75 | }
76 | 


--------------------------------------------------------------------------------
/app/src/main/java/org/bepass/oblivion/SplitTunnelOptionsAdapter.java:
--------------------------------------------------------------------------------
 1 | package org.bepass.oblivion;
 2 | 
 3 | import android.content.Context;
 4 | import android.view.LayoutInflater;
 5 | import android.view.View;
 6 | import android.view.ViewGroup;
 7 | import android.widget.RadioButton;
 8 | 
 9 | import androidx.annotation.NonNull;
10 | import androidx.recyclerview.widget.RecyclerView;
11 | 
12 | import com.google.android.material.switchmaterial.SwitchMaterial;
13 | 
14 | import org.bepass.oblivion.enums.SplitTunnelMode;
15 | import org.bepass.oblivion.utils.FileManager;
16 | 
17 | public class SplitTunnelOptionsAdapter extends RecyclerView.Adapter<SplitTunnelOptionsAdapter.ViewHolder> {
18 | 
19 |     private final OnSettingsChanged settingsCallback;
20 | 
21 | 
22 |     public SplitTunnelOptionsAdapter(Context context, OnSettingsChanged settingsCallback) {
23 |         this.settingsCallback = settingsCallback;
24 |     }
25 | 
26 | 
27 |     @NonNull
28 |     @Override
29 |     public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
30 |         View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.split_tunnel_options, parent, false);
31 |         return new ViewHolder(view);
32 |     }
33 | 
34 |     @Override
35 |     public void onBindViewHolder(@NonNull ViewHolder holder, int position) {
36 |         SplitTunnelMode stm = SplitTunnelMode.getSplitTunnelMode();
37 |         switch (stm) {
38 |             case DISABLED:
39 |                 holder.disabled.setChecked(true);
40 |                 break;
41 |             case BLACKLIST:
42 |                 holder.blacklist.setChecked(true);
43 |                 break;
44 |         }
45 |         holder.showSystemApps.setOnCheckedChangeListener((buttonView, isChecked) -> settingsCallback.shouldShowSystemApps(isChecked));
46 |         holder.disabled.setOnCheckedChangeListener((buttonView, isChecked) -> {
47 |             if (isChecked) {
48 |                 settingsCallback.splitTunnelMode(SplitTunnelMode.DISABLED);
49 |                 FileManager.set("splitTunnelMode", SplitTunnelMode.DISABLED.toString());
50 |             }
51 |         });
52 |         holder.blacklist.setOnCheckedChangeListener((buttonView, isChecked) -> {
53 |             if (isChecked) {
54 |                 settingsCallback.splitTunnelMode(SplitTunnelMode.BLACKLIST);
55 |                 FileManager.set("splitTunnelMode", SplitTunnelMode.BLACKLIST.toString());
56 |             }
57 | 
58 |         });
59 |     }
60 | 
61 |     @Override
62 |     public int getItemCount() {
63 |         return 1; // Header has only one item
64 |     }
65 | 
66 |     public interface OnSettingsChanged {
67 |         void splitTunnelMode(SplitTunnelMode mode);
68 | 
69 |         void shouldShowSystemApps(boolean show);
70 |     }
71 | 
72 |     public static class ViewHolder extends RecyclerView.ViewHolder {
73 |         SwitchMaterial showSystemApps;
74 |         RadioButton disabled;
75 |         RadioButton blacklist;
76 | 
77 |         public ViewHolder(@NonNull View itemView) {
78 |             super(itemView);
79 |             showSystemApps = itemView.findViewById(R.id.showSystemApps);
80 |             disabled = itemView.findViewById(R.id.disabled);
81 |             blacklist = itemView.findViewById(R.id.blacklist);
82 |         }
83 |     }
84 | }


--------------------------------------------------------------------------------
/app/src/main/java/org/bepass/oblivion/base/ApplicationLoader.java:
--------------------------------------------------------------------------------
 1 | package org.bepass.oblivion.base;
 2 | 
 3 | import android.app.Application;
 4 | import android.content.Context;
 5 | 
 6 | import androidx.appcompat.app.AppCompatDelegate;
 7 | 
 8 | import org.bepass.oblivion.utils.FileManager;
 9 | import org.bepass.oblivion.utils.ThemeHelper;
10 | 
11 | /**
12 |  * ApplicationLoader is a custom Application class that extends the Android Application class.
13 |  * It is designed to provide a centralized context reference throughout the application.
14 |  */
15 | public class ApplicationLoader extends Application {
16 | 
17 |     // Tag for logging purposes
18 |     private static final String TAG = "ApplicationLoader";
19 | 
20 |     /**
21 |      * This method is called when the application is starting, before any activity, service, or receiver objects (excluding content providers) have been created.
22 |      *
23 |      * @see android.app.Application#onCreate()
24 |      */
25 |     @Override
26 |     public void onCreate() {
27 |         super.onCreate();
28 |         FileManager.initialize(this); // Initialize FileManager with Application context
29 |         ThemeHelper.getInstance().init();
30 |         ThemeHelper.getInstance().applyTheme();
31 |     }
32 | }


--------------------------------------------------------------------------------
/app/src/main/java/org/bepass/oblivion/base/BaseActivity.java:
--------------------------------------------------------------------------------
 1 | package org.bepass.oblivion.base;
 2 | 
 3 | import android.os.Build;
 4 | import android.os.Bundle;
 5 | 
 6 | import androidx.annotation.Nullable;
 7 | import androidx.appcompat.app.AppCompatActivity;
 8 | import androidx.databinding.DataBindingUtil;
 9 | import androidx.databinding.ViewDataBinding;
10 | 
11 | import org.bepass.oblivion.utils.ColorUtils;
12 | import org.bepass.oblivion.utils.FileManager;
13 | import org.bepass.oblivion.utils.SystemUtils;
14 | 
15 | /**
16 |  * BaseActivity is an abstract class serving as a base for activities in an Android application.
17 |  * It extends the AppCompatActivity class and utilizes Android's data binding framework.
18 |  * @param <B> The type of ViewDataBinding associated with the activity.
19 |  */
20 | public abstract class BaseActivity<B extends ViewDataBinding> extends AppCompatActivity {
21 | 
22 |     // ViewDataBinding instance associated with the activity layout
23 |     protected B binding;
24 | 
25 |     // Tag for logging purposes
26 |     protected String TAG = this.getClass().getSimpleName();
27 | 
28 |     /**
29 |      * Abstract method to be implemented by subclasses to provide the layout resource ID for the activity.
30 |      * @return The layout resource ID.
31 |      */
32 |     protected abstract int getLayoutResourceId();
33 | 
34 |     protected abstract int getStatusBarColor();
35 | 
36 |     /**
37 |      * Called when the activity is starting.
38 |      * @param savedInstanceState If the activity is being re-initialized after previously being shut down then this Bundle contains the data it most recently supplied in onSaveInstanceState(Bundle).
39 |      * @see AppCompatActivity#onCreate(Bundle)
40 |      */
41 |     @Override
42 |     protected void onCreate(@Nullable Bundle savedInstanceState) {
43 |         super.onCreate(savedInstanceState);
44 |         FileManager.initialize(this); // Initialize FileManager with Activity context
45 |         // Inflates the layout and initializes the binding object
46 |         binding = DataBindingUtil.setContentView(this, getLayoutResourceId());
47 |         if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
48 |             SystemUtils.setStatusBarColor(
49 |                     this, getStatusBarColor(), ColorUtils.isColorDark(getStatusBarColor())
50 |             );
51 |         }
52 |     }
53 | }


--------------------------------------------------------------------------------
/app/src/main/java/org/bepass/oblivion/base/StateAwareBaseActivity.java:
--------------------------------------------------------------------------------
  1 | package org.bepass.oblivion.base;
  2 | 
  3 | import android.content.ComponentName;
  4 | import android.content.Context;
  5 | import android.content.Intent;
  6 | import android.content.ServiceConnection;
  7 | import android.os.Build;
  8 | import android.os.Bundle;
  9 | import android.os.IBinder;
 10 | import android.os.Messenger;
 11 | import android.util.Log;
 12 | 
 13 | import androidx.annotation.Nullable;
 14 | import androidx.appcompat.app.AppCompatActivity;
 15 | import androidx.databinding.DataBindingUtil;
 16 | import androidx.databinding.ViewDataBinding;
 17 | 
 18 | import org.bepass.oblivion.enums.ConnectionState;
 19 | import org.bepass.oblivion.service.OblivionVpnService;
 20 | import org.bepass.oblivion.utils.ColorUtils;
 21 | import org.bepass.oblivion.utils.FileManager;
 22 | import org.bepass.oblivion.utils.SystemUtils;
 23 | 
 24 | /**
 25 |  * Activities inheriting from this class observe connection state by default and have access to lastKnownConnectionState variable.
 26 |  */
 27 | public abstract class StateAwareBaseActivity<B extends ViewDataBinding> extends AppCompatActivity {
 28 |     private static final String TAG = "StateAwareBaseActivity";
 29 | 
 30 |     protected ConnectionState lastKnownConnectionState = ConnectionState.DISCONNECTED;
 31 |     private static boolean requireRestartVpnService = false;
 32 |     protected B binding;
 33 |     private Messenger serviceMessenger;
 34 |     private boolean isBound;
 35 | 
 36 |     protected abstract int getLayoutResourceId();
 37 | 
 38 |     protected abstract int getStatusBarColor();
 39 | 
 40 |     @Override
 41 |     protected void onCreate(@Nullable Bundle savedInstanceState) {
 42 |         super.onCreate(savedInstanceState);
 43 |         FileManager.initialize(this); // Initialize FileManager with Activity context
 44 |         binding = DataBindingUtil.setContentView(this, getLayoutResourceId());
 45 |         if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
 46 |             SystemUtils.setStatusBarColor(
 47 |                     this, getStatusBarColor(), ColorUtils.isColorDark(getStatusBarColor())
 48 |             );
 49 |         }
 50 |     }
 51 | 
 52 |     public static boolean getRequireRestartVpnService() {
 53 |         return requireRestartVpnService;
 54 |     }
 55 | 
 56 |     public static void setRequireRestartVpnService(boolean b) {
 57 |         StateAwareBaseActivity.requireRestartVpnService = b;
 58 |     }
 59 | 
 60 |     private final ServiceConnection connection = new ServiceConnection() {
 61 |         @Override
 62 |         public void onServiceConnected(ComponentName className, IBinder service) {
 63 |             serviceMessenger = new Messenger(service);
 64 |             isBound = true;
 65 |             observeConnectionStatus();
 66 |         }
 67 | 
 68 |         @Override
 69 |         public void onServiceDisconnected(ComponentName arg0) {
 70 |             serviceMessenger = null;
 71 |             isBound = false;
 72 |         }
 73 |     };
 74 | 
 75 |     protected abstract String getKey();
 76 | 
 77 |     protected abstract void onConnectionStateChange(ConnectionState state);
 78 | 
 79 |     public void observeConnectionStatus() {
 80 |         if (!isBound || serviceMessenger == null) {
 81 |             Log.w(TAG, "Service is not bound or messenger is null");
 82 |             return;
 83 |         }
 84 | 
 85 |         OblivionVpnService.registerConnectionStateObserver(getKey(), serviceMessenger, state -> {
 86 |             if (lastKnownConnectionState == state) return;
 87 |             lastKnownConnectionState = state;
 88 |             onConnectionStateChange(state);
 89 |         });
 90 |     }
 91 | 
 92 |     private void unsubscribeConnectionStatus() {
 93 |         if (!isBound || serviceMessenger == null) {
 94 |             Log.w(TAG, "Service is not bound or messenger is null");
 95 |             return;
 96 |         }
 97 | 
 98 |         OblivionVpnService.unregisterConnectionStateObserver(getKey(), serviceMessenger);
 99 |     }
100 | 
101 |     @Override
102 |     protected void onStart() {
103 |         super.onStart();
104 |         bindService(new Intent(this, OblivionVpnService.class), connection, Context.BIND_AUTO_CREATE);
105 |     }
106 | 
107 |     @Override
108 |     protected void onStop() {
109 |         super.onStop();
110 |         if (isBound) {
111 |             unsubscribeConnectionStatus();
112 |             unbindService(connection);
113 |             isBound = false;
114 |         }
115 |     }
116 | }


--------------------------------------------------------------------------------
/app/src/main/java/org/bepass/oblivion/component/Icon.java:
--------------------------------------------------------------------------------
 1 | package org.bepass.oblivion.component;
 2 | 
 3 | import android.annotation.SuppressLint;
 4 | import android.content.Context;
 5 | import android.content.res.TypedArray;
 6 | import android.graphics.PorterDuff;
 7 | import android.net.Uri;
 8 | import android.util.AttributeSet;
 9 | import android.view.MotionEvent;
10 | 
11 | import androidx.annotation.NonNull;
12 | import androidx.annotation.Nullable;
13 | import androidx.appcompat.widget.AppCompatImageView;
14 | import androidx.core.content.ContextCompat;
15 | 
16 | import org.bepass.oblivion.R;
17 | 
18 | import java.io.File;
19 | 
20 | public class Icon extends AppCompatImageView {
21 |     private boolean hasBounceAnimation;
22 |     private boolean isPrimaryIcon;
23 | 
24 |     public Icon(@NonNull Context context) {
25 |         super(context);
26 |         if (!isInEditMode())init();
27 |     }
28 | 
29 |     public Icon(@NonNull Context context, @Nullable AttributeSet attrs) {
30 |         super(context, attrs);
31 |         if (!isInEditMode()){
32 |             setupAttrs(context, attrs, 0);
33 |             init();
34 |         }
35 |     }
36 | 
37 |     public Icon(@NonNull Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
38 |         super(context, attrs, defStyleAttr);
39 |         if (!isInEditMode()){
40 |             setupAttrs(context, attrs, defStyleAttr);
41 |             init();
42 |         }
43 |     }
44 | 
45 |     private void setupAttrs(@NonNull Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
46 |         TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.Icon, defStyleAttr, 0);
47 |         try {
48 |             int color = a.getColor(R.styleable.Icon_icon_color, 0);
49 |             if (color != 0) {
50 |                 setColorFilter(color, PorterDuff.Mode.SRC_ATOP);
51 |             }
52 |         }  finally {
53 |             a.recycle();
54 |         }
55 |     }
56 | 
57 |     @SuppressLint("ClickableViewAccessibility")
58 |     @Override
59 |     public boolean onTouchEvent(MotionEvent event) {
60 |         if (event.getAction() == MotionEvent.ACTION_DOWN) {
61 | //            if (hasBounceAnimation)
62 | //                AnimationHelper.startPushButtonAnimation(this);
63 |         }
64 |         return super.onTouchEvent(event);
65 | 
66 |     }
67 | 
68 |     public void changeColor(int color) {
69 |         if (color != 0) {
70 |             setColorFilter(color, PorterDuff.Mode.SRC_ATOP);
71 |         }
72 |     }
73 | 
74 |     private void init() {
75 |     }
76 | }


--------------------------------------------------------------------------------
/app/src/main/java/org/bepass/oblivion/component/TouchAwareSwitch.java:
--------------------------------------------------------------------------------
 1 | package org.bepass.oblivion.component;
 2 | 
 3 | import android.annotation.SuppressLint;
 4 | import android.content.Context;
 5 | import android.util.AttributeSet;
 6 | 
 7 | import com.suke.widget.SwitchButton;
 8 | 
 9 | public class TouchAwareSwitch extends SwitchButton {
10 | 
11 |     public TouchAwareSwitch(Context context) {
12 |         super(context);
13 |     }
14 | 
15 |     public TouchAwareSwitch(Context context, AttributeSet attrs) {
16 |         super(context, attrs);
17 |     }
18 | 
19 |     public TouchAwareSwitch(Context context, AttributeSet attrs, int defStyleAttr) {
20 |         super(context, attrs, defStyleAttr);
21 |     }
22 | 
23 |     @SuppressLint("ClickableViewAccessibility")
24 |     @Override
25 |     public void setOnCheckedChangeListener(final OnCheckedChangeListener listener) {
26 |         setOnTouchListener((v, event) -> {
27 |             setTag(null);
28 |             return false;
29 |         });
30 | 
31 |         super.setOnCheckedChangeListener((view, isChecked) -> {
32 |             if (getTag() != null) {
33 |                 setTag(null);
34 |                 return;
35 |             }
36 |             listener.onCheckedChanged(view, isChecked);
37 |         });
38 |     }
39 | 
40 |     public void setChecked(boolean checked, boolean notify) {
41 |         if (!notify) setTag("TAG");
42 |         setChecked(checked);
43 |     }
44 | }
45 | 


--------------------------------------------------------------------------------
/app/src/main/java/org/bepass/oblivion/enums/ConnectionState.java:
--------------------------------------------------------------------------------
 1 | package org.bepass.oblivion.enums;
 2 | 
 3 | public enum ConnectionState {
 4 |     CONNECTING, CONNECTED, DISCONNECTED;
 5 | 
 6 |     public boolean isDisconnected() {
 7 |         return this == DISCONNECTED;
 8 |     }
 9 |     public boolean isConnecting(){
10 |         return this == CONNECTING;
11 |     }
12 | }
13 | 


--------------------------------------------------------------------------------
/app/src/main/java/org/bepass/oblivion/enums/SplitTunnelMode.java:
--------------------------------------------------------------------------------
 1 | package org.bepass.oblivion.enums;
 2 | 
 3 | import org.bepass.oblivion.utils.FileManager;
 4 | 
 5 | public enum SplitTunnelMode {
 6 |     DISABLED,
 7 |     BLACKLIST;
 8 | 
 9 |     public static SplitTunnelMode getSplitTunnelMode() {
10 |         SplitTunnelMode splitTunnelMode;
11 |         try {
12 |             splitTunnelMode = SplitTunnelMode.valueOf(FileManager.getString("splitTunnelMode", SplitTunnelMode.DISABLED.toString()));
13 |         } catch (Exception e) {
14 |             splitTunnelMode = SplitTunnelMode.DISABLED;
15 |         }
16 |         return splitTunnelMode;
17 |     }
18 | }
19 | 


--------------------------------------------------------------------------------
/app/src/main/java/org/bepass/oblivion/interfaces/ConnectionStateChangeListener.java:
--------------------------------------------------------------------------------
1 | package org.bepass.oblivion.interfaces;
2 | 
3 | import org.bepass.oblivion.enums.ConnectionState;
4 | 
5 | public interface ConnectionStateChangeListener {
6 |     void onChange(ConnectionState state);
7 | }
8 | 


--------------------------------------------------------------------------------
/app/src/main/java/org/bepass/oblivion/interfaces/SheetsCallBack.java:
--------------------------------------------------------------------------------
1 | package org.bepass.oblivion.interfaces;
2 | 
3 | public interface SheetsCallBack {
4 |     void onSheetClosed();
5 | }
6 | 


--------------------------------------------------------------------------------
/app/src/main/java/org/bepass/oblivion/model/IPDetails.java:
--------------------------------------------------------------------------------
1 | package org.bepass.oblivion.model;
2 | 
3 | public class IPDetails {
4 |     public String ip;
5 |     public String country;
6 |     public String flag;
7 | }
8 | 


--------------------------------------------------------------------------------
/app/src/main/java/org/bepass/oblivion/service/QuickStartService.java:
--------------------------------------------------------------------------------
  1 | package org.bepass.oblivion.service;
  2 | 
  3 | import static org.bepass.oblivion.ui.MainActivity.startVpnService;
  4 | 
  5 | import android.content.ComponentName;
  6 | import android.content.Context;
  7 | import android.content.Intent;
  8 | import android.content.ServiceConnection;
  9 | import android.graphics.drawable.Icon;
 10 | import android.os.Build;
 11 | import android.os.IBinder;
 12 | import android.os.Messenger;
 13 | import android.service.quicksettings.Tile;
 14 | import android.service.quicksettings.TileService;
 15 | import android.widget.Toast;
 16 | 
 17 | import androidx.annotation.RequiresApi;
 18 | 
 19 | import org.bepass.oblivion.R;
 20 | 
 21 | @RequiresApi(api = Build.VERSION_CODES.N)
 22 | public class QuickStartService extends TileService {
 23 |     private final static String CONNECTION_OBSERVER_KEY = "quickstartToggleButton";
 24 |     private boolean isBound;
 25 |     private Messenger serviceMessenger;
 26 |     private final ServiceConnection connection = new ServiceConnection() {
 27 |         @Override
 28 |         public void onServiceConnected(ComponentName className, IBinder service) {
 29 |             serviceMessenger = new Messenger(service);
 30 |             isBound = true;
 31 |             subscribe();
 32 |         }
 33 | 
 34 |         @Override
 35 |         public void onServiceDisconnected(ComponentName arg0) {
 36 |             serviceMessenger = null;
 37 |             isBound = false;
 38 |         }
 39 |     };
 40 | 
 41 | 
 42 |     // Called when your app can update your tile.
 43 |     @Override
 44 |     public void onStartListening() {
 45 |         bindService(new Intent(this, OblivionVpnService.class), connection, Context.BIND_AUTO_CREATE);
 46 |     }
 47 | 
 48 |     // Called when your app can no longer update your tile.
 49 |     @Override
 50 |     public void onStopListening() {
 51 |         // Unbind from the service
 52 |         if (isBound) {
 53 |             unsubscribe();
 54 |             isBound = false;
 55 |         }
 56 |         try {
 57 |             unbindService(connection);
 58 |         } catch (Exception e) {
 59 |             //Swallow unbound unbind exceptions
 60 |         }
 61 |     }
 62 | 
 63 |     // Called when the user taps on your tile in an active or inactive state.
 64 |     @Override
 65 |     public void onClick() {
 66 |         Tile tile = getQsTile();
 67 |         if (tile == null) {
 68 |             return; //Quick setting tile was not registered by system. Return to prevent crash
 69 |         }
 70 | 
 71 |         if (tile.getState() == Tile.STATE_ACTIVE) {
 72 |             OblivionVpnService.stopVpnService(this);
 73 |             return;
 74 |         }
 75 | 
 76 |         if (OblivionVpnService.prepare(this) != null) {
 77 |             Toast.makeText(this, "لطفا یک‌بار از درون اپلیکیشن متصل شوید", Toast.LENGTH_LONG).show();
 78 |             return;
 79 |         }
 80 |         Intent vpnIntent = new Intent(this, OblivionVpnService.class);
 81 |         startVpnService(this, vpnIntent);
 82 |     }
 83 | 
 84 |     private void subscribe() {
 85 |         if (!isBound) return;
 86 |         OblivionVpnService.registerConnectionStateObserver(CONNECTION_OBSERVER_KEY, serviceMessenger, state -> {
 87 |             Tile tile = getQsTile();
 88 |             if (tile == null) {
 89 |                 return; //Quick setting tile was not registered by system. Return to prevent crash
 90 |             }
 91 |             switch (state) {
 92 |                 case DISCONNECTED:
 93 |                     tile.setState(Tile.STATE_INACTIVE);
 94 |                     tile.setLabel("Oblivion");
 95 |                     tile.setIcon(Icon.createWithResource(getApplicationContext(), R.drawable.vpn_off));
 96 |                     tile.updateTile();
 97 |                     break;
 98 |                 case CONNECTING:
 99 |                     tile.setState(Tile.STATE_ACTIVE);
100 |                     tile.setLabel("Connecting");
101 |                     tile.setIcon(Icon.createWithResource(getApplicationContext(), R.drawable.vpn_off));
102 |                     tile.updateTile();
103 |                     break;
104 |                 case CONNECTED:
105 |                     tile.setState(Tile.STATE_ACTIVE);
106 |                     tile.setLabel("Connected");
107 |                     tile.setIcon(Icon.createWithResource(getApplicationContext(), R.drawable.vpn_on));
108 |                     tile.updateTile();
109 |             }
110 |         });
111 |     }
112 | 
113 |     private void unsubscribe() {
114 |         if (!isBound) return;
115 |         OblivionVpnService.unregisterConnectionStateObserver(CONNECTION_OBSERVER_KEY, serviceMessenger);
116 |     }
117 | }
118 | 


--------------------------------------------------------------------------------
/app/src/main/java/org/bepass/oblivion/ui/InfoActivity.java:
--------------------------------------------------------------------------------
 1 |     package org.bepass.oblivion.ui;
 2 | 
 3 |     import android.content.Intent;
 4 |     import android.net.Uri;
 5 |     import android.os.Bundle;
 6 | 
 7 |     import org.bepass.oblivion.R;
 8 |     import org.bepass.oblivion.base.BaseActivity;
 9 |     import org.bepass.oblivion.databinding.ActivityInfoBinding;
10 |     import org.bepass.oblivion.utils.ThemeHelper;
11 | 
12 |     public class InfoActivity extends BaseActivity<ActivityInfoBinding> {
13 | 
14 |         @Override
15 |         protected int getLayoutResourceId() {
16 |             return R.layout.activity_info;
17 |         }
18 | 
19 |         @Override
20 |         protected int getStatusBarColor() {
21 |             return R.color.status_bar_color;
22 |         }
23 | 
24 |         @Override
25 |         protected void onCreate(Bundle savedInstanceState) {
26 |             super.onCreate(savedInstanceState);
27 | 
28 |             // Update background based on current theme
29 |             ThemeHelper.getInstance().updateActivityBackground(binding.getRoot());
30 | 
31 |             binding.githubLayout.setOnClickListener(v -> {
32 |                 Uri uri = Uri.parse("https://github.com/bepass-org/oblivion");
33 |                 Intent intent = new Intent(Intent.ACTION_VIEW, uri);
34 |                 startActivity(intent);
35 |             });
36 | 
37 |             binding.back.setOnClickListener(v -> getOnBackPressedDispatcher().onBackPressed());
38 |         }
39 |     }
40 | 


--------------------------------------------------------------------------------
/app/src/main/java/org/bepass/oblivion/ui/LogActivity.java:
--------------------------------------------------------------------------------
  1 | package org.bepass.oblivion.ui;
  2 | 
  3 | import android.content.ClipData;
  4 | import android.content.ClipboardManager;
  5 | import android.content.Context;
  6 | import android.os.Bundle;
  7 | import android.os.Handler;
  8 | import android.os.Looper;
  9 | import android.view.LayoutInflater;
 10 | import android.view.View;
 11 | import android.widget.FrameLayout;
 12 | import android.widget.ProgressBar;
 13 | import android.widget.ScrollView;
 14 | import android.widget.TextView;
 15 | import android.widget.Toast;
 16 | 
 17 | import org.bepass.oblivion.R;
 18 | import org.bepass.oblivion.base.BaseActivity;
 19 | import org.bepass.oblivion.databinding.ActivityLogBinding;
 20 | import org.bepass.oblivion.utils.ISPUtils;
 21 | import org.bepass.oblivion.utils.ThemeHelper;
 22 | 
 23 | import java.io.BufferedReader;
 24 | import java.io.IOException;
 25 | import java.io.InputStreamReader;
 26 | import java.util.ArrayDeque;
 27 | import java.util.Arrays;
 28 | import java.util.Deque;
 29 | 
 30 | public class LogActivity extends BaseActivity<ActivityLogBinding> {
 31 | 
 32 |     private final Handler handler = new Handler(Looper.getMainLooper());
 33 |     private boolean isUserScrollingUp = false;
 34 |     private Runnable logUpdater;
 35 |     private FrameLayout progressBar;
 36 | 
 37 |     @Override
 38 |     protected int getLayoutResourceId() {
 39 |         return R.layout.activity_log;
 40 |     }
 41 | 
 42 |     @Override
 43 |     protected int getStatusBarColor() {
 44 |         return R.color.status_bar_color;
 45 |     }
 46 | 
 47 |     @Override
 48 |     protected void onCreate(Bundle savedInstanceState) {
 49 |         super.onCreate(savedInstanceState);
 50 |         // Update background based on current theme
 51 |         ThemeHelper.getInstance().updateActivityBackground(binding.getRoot());
 52 | 
 53 |         // Initialize the ProgressBar
 54 |         progressBar = findViewById(R.id.progress_container);
 55 |         binding.back.setOnClickListener(v -> getOnBackPressedDispatcher().onBackPressed());
 56 |         binding.copytoclip.setOnClickListener(v -> copyLast100LinesToClipboard());
 57 |         setupScrollListener();
 58 | 
 59 |         logUpdater = new Runnable() {
 60 |             @Override
 61 |             public void run() {
 62 |                 readLogsFromFile();
 63 |                 handler.postDelayed(this, 2000); // Refresh every 2 seconds
 64 |             }
 65 |         };
 66 |     }
 67 | 
 68 |     private void setupScrollListener() {
 69 |         binding.logScrollView.getViewTreeObserver().addOnScrollChangedListener(() -> {
 70 |             int scrollY = binding.logScrollView.getScrollY();
 71 |             int maxScrollY = binding.logs.getHeight() - binding.logScrollView.getHeight();
 72 |             isUserScrollingUp = scrollY < maxScrollY;
 73 |         });
 74 |     }
 75 | 
 76 |     @Override
 77 |     protected void onResume() {
 78 |         super.onResume();
 79 |         handler.post(logUpdater);
 80 |     }
 81 | 
 82 |     @Override
 83 |     protected void onPause() {
 84 |         super.onPause();
 85 |         handler.removeCallbacks(logUpdater);
 86 |     }
 87 | 
 88 |     private void readLogsFromFile() {
 89 |         try (BufferedReader reader = new BufferedReader(new InputStreamReader(openFileInput("logs.txt")))) {
 90 |             StringBuilder sb = new StringBuilder();
 91 |             String line;
 92 | 
 93 |             while ((line = reader.readLine()) != null) {
 94 |                 sb.append(line).append("\n");
 95 |             }
 96 | 
 97 |             String finalLog = sb.toString();
 98 |             runOnUiThread(() -> {
 99 |                 binding.logs.setText(finalLog);
100 |                 if (!isUserScrollingUp) {
101 |                     binding.logScrollView.post(() -> binding.logScrollView.fullScroll(ScrollView.FOCUS_DOWN));
102 |                 }
103 |             });
104 |         } catch (IOException e) {
105 |             e.printStackTrace();
106 |         }
107 |     }
108 | 
109 |     private void copyLast100LinesToClipboard() {
110 |         // Show progress bar
111 |         progressBar.setVisibility(View.VISIBLE);
112 | 
113 |         ISPUtils.fetchISPInfo(new ISPUtils.ISPCallback() {
114 |             @Override
115 |             public void onISPInfoReceived(String isp) {
116 |                 runOnUiThread(() -> {
117 |                     // Hide progress bar
118 |                     progressBar.setVisibility(View.GONE);
119 | 
120 |                     String logText = binding.logs.getText().toString();
121 |                     String[] logLines = logText.split("\n");
122 |                     int totalLines = logLines.length;
123 | 
124 |                     // Use Deque to efficiently get the last 100 lines
125 |                     Deque<String> last100Lines = new ArrayDeque<>(100);
126 |                     last100Lines.addAll(Arrays.asList(logLines).subList(Math.max(0, totalLines - 100), totalLines));
127 | 
128 |                     StringBuilder sb = new StringBuilder();
129 |                     for (String line : last100Lines) {
130 |                         sb.append(line).append("\n");
131 |                     }
132 | 
133 |                     // Add ISP information
134 |                     sb.append("\n=====\nISP: ").append(isp).append("\n");
135 | 
136 |                     String last100Log = sb.toString();
137 |                     ClipboardManager clipboard = (ClipboardManager) getSystemService(Context.CLIPBOARD_SERVICE);
138 |                     ClipData clip = ClipData.newPlainText("Log", last100Log);
139 |                     clipboard.setPrimaryClip(clip);
140 | 
141 |                     showCopiedToClipboardToast();
142 |                 });
143 |             }
144 | 
145 |             @Override
146 |             public void onError(Exception e) {
147 |                 runOnUiThread(() -> {
148 |                     // Hide progress bar
149 |                     progressBar.setVisibility(View.GONE);
150 | 
151 |                     e.printStackTrace();
152 |                     Toast.makeText(LogActivity.this, "Error fetching ISP information.", Toast.LENGTH_SHORT).show();
153 |                 });
154 |             }
155 |         });
156 |     }
157 | 
158 |     private void showCopiedToClipboardToast() {
159 |         LayoutInflater inflater = getLayoutInflater();
160 |         View layout = inflater.inflate(R.layout.toast, findViewById(R.id.toast_layout));
161 | 
162 |         Toast toast = new Toast(getApplicationContext());
163 |         toast.setDuration(Toast.LENGTH_SHORT);
164 |         toast.setView(layout);
165 |         toast.show();
166 |     }
167 | }


--------------------------------------------------------------------------------
/app/src/main/java/org/bepass/oblivion/ui/SplashScreenActivity.java:
--------------------------------------------------------------------------------
 1 | package org.bepass.oblivion.ui;
 2 | 
 3 | import android.annotation.SuppressLint;
 4 | import android.os.Bundle;
 5 | import android.os.Handler;
 6 | import android.view.View;
 7 | 
 8 | import org.bepass.oblivion.R;
 9 | import org.bepass.oblivion.base.ApplicationLoader;
10 | import org.bepass.oblivion.base.BaseActivity;
11 | import org.bepass.oblivion.databinding.ActivitySplashScreenBinding;
12 | import org.bepass.oblivion.utils.FileManager;
13 | import org.bepass.oblivion.utils.LocaleHandler;
14 | import org.bepass.oblivion.utils.ThemeHelper;
15 | 
16 | /**
17 |  * A simple splash screen activity that shows a splash screen for a short duration before navigating
18 |  * to the main activity. This class extends {@link BaseActivity} and uses data binding.
19 |  */
20 | @SuppressLint("CustomSplashScreen")
21 | public class SplashScreenActivity extends BaseActivity<ActivitySplashScreenBinding> {
22 |     /**
23 |      * Returns the layout resource ID for the splash screen activity.
24 |      *
25 |      * @return The layout resource ID.
26 |      */
27 |     @Override
28 |     protected int getLayoutResourceId() {
29 |         return R.layout.activity_splash_screen;
30 |     }
31 | 
32 |     @Override
33 |     protected int getStatusBarColor() {
34 |         return R.color.status_bar_color;
35 |     }
36 | 
37 |     /**
38 |      * Called when the activity is first created. This method sets up the splash screen and
39 |      * schedules the transition to the main activity.
40 |      *
41 |      * @param savedInstanceState If the activity is being re-initialized after previously being shut down
42 |      *                           then this Bundle contains the data it most recently supplied in onSaveInstanceState(Bundle).
43 |      */
44 |     @Override
45 |     protected void onCreate(Bundle savedInstanceState) {
46 |         super.onCreate(savedInstanceState);
47 |         LocaleHandler localeHandler = new LocaleHandler(this);
48 |         localeHandler.setPersianAsDefaultLocaleIfNeeds();
49 |         // Update background based on current theme
50 |         ThemeHelper.getInstance().updateActivityBackground(binding.getRoot());
51 | 
52 |         binding.setHandler(new ClickHandler());
53 |         // 1 second
54 |         int SHORT_SPLASH_DISPLAY_LENGTH = 1000;
55 |         new Handler().postDelayed(() -> {
56 |             // First locale change to persian cause activity recreation
57 |             // with this check we can sure we don't do start twice
58 |             if (isDestroyed()) return;
59 | 
60 |             MainActivity.start(this);
61 |             finish();
62 |         }, SHORT_SPLASH_DISPLAY_LENGTH);
63 |     }
64 | 
65 |     /**
66 |      * A click handler for handling user interactions with the splash screen.
67 |      */
68 |     public class ClickHandler {
69 | 
70 |         /**
71 |          * Called when the root view is pressed. This method immediately navigates to the main activity
72 |          * and finishes the splash screen activity.
73 |          *
74 |          * @param view The view that was clicked.
75 |          */
76 |         public void OnRootPressed(View view) {
77 |             MainActivity.start(SplashScreenActivity.this);
78 |             finish();
79 |         }
80 |     }
81 | 
82 | }
83 | 


--------------------------------------------------------------------------------
/app/src/main/java/org/bepass/oblivion/ui/SplitTunnelActivity.java:
--------------------------------------------------------------------------------
 1 | package org.bepass.oblivion.ui;
 2 | 
 3 | import android.os.Bundle;
 4 | import android.view.View;
 5 | 
 6 | import androidx.annotation.NonNull;
 7 | import androidx.recyclerview.widget.ConcatAdapter;
 8 | 
 9 | import org.bepass.oblivion.BypassListAppsAdapter;
10 | import org.bepass.oblivion.enums.ConnectionState;
11 | import org.bepass.oblivion.utils.FileManager;
12 | import org.bepass.oblivion.R;
13 | import org.bepass.oblivion.enums.SplitTunnelMode;
14 | import org.bepass.oblivion.SplitTunnelOptionsAdapter;
15 | import org.bepass.oblivion.base.StateAwareBaseActivity;
16 | import org.bepass.oblivion.databinding.ActivitySplitTunnelBinding;
17 | import org.bepass.oblivion.utils.ThemeHelper;
18 | 
19 | 
20 | public class SplitTunnelActivity extends StateAwareBaseActivity<ActivitySplitTunnelBinding> {
21 | 
22 |     @Override
23 |     protected int getLayoutResourceId() {
24 |         return R.layout.activity_split_tunnel;
25 |     }
26 | 
27 |     @Override
28 |     protected int getStatusBarColor() {
29 |         return R.color.status_bar_color;
30 |     }
31 | 
32 |     @Override
33 |     protected void onCreate(Bundle savedInstanceState) {
34 |         super.onCreate(savedInstanceState);
35 |         // Update background based on current theme
36 |         ThemeHelper.getInstance().updateActivityBackground(binding.getRoot());
37 | 
38 |         // Handles the back button behaviour
39 |         binding.back.setOnClickListener(v -> getOnBackPressedDispatcher().onBackPressed());
40 | 
41 |         // Set up the app list
42 |         BypassListAppsAdapter bypassListAppsAdapter = new BypassListAppsAdapter(this, loading -> {
43 |             binding.appsRecycler.setVisibility(loading ? View.INVISIBLE : View.VISIBLE);
44 |                 if (loading) binding.progress.show();
45 |                 else binding.progress.hide();
46 |         });
47 | 
48 |         // Signal the need to restart the VPN service on app selection change
49 |         bypassListAppsAdapter.setOnAppSelectListener((packageName, selected) -> {
50 |             StateAwareBaseActivity.setRequireRestartVpnService(true);
51 |         });
52 | 
53 |         // Set behaviour for Split tunnel options
54 |         SplitTunnelOptionsAdapter optionsAdapter = new SplitTunnelOptionsAdapter(this, new SplitTunnelOptionsAdapter.OnSettingsChanged() {
55 |             @Override
56 |             public void splitTunnelMode(SplitTunnelMode mode) {
57 |                 StateAwareBaseActivity.setRequireRestartVpnService(true);
58 |                 FileManager.set("splitTunnelMode", mode.toString());
59 |             }
60 | 
61 |             @Override
62 |             public void shouldShowSystemApps(boolean show) {
63 |                 bypassListAppsAdapter.setShouldShowSystemApps(SplitTunnelActivity.this, show);
64 |             }
65 |         });
66 | 
67 |         binding.appsRecycler.setAdapter(new ConcatAdapter(optionsAdapter, bypassListAppsAdapter));
68 |     }
69 | 
70 |     @Override
71 |     public void onConnectionStateChange(ConnectionState state) { }
72 | 
73 |     @NonNull
74 |     @Override
75 |     public String getKey() { return "splitTunnelActivity"; }
76 | }
77 | 


--------------------------------------------------------------------------------
/app/src/main/java/org/bepass/oblivion/utils/BatteryOptimization.kt:
--------------------------------------------------------------------------------
 1 | package org.bepass.oblivion.utils
 2 | 
 3 | import android.annotation.SuppressLint
 4 | import android.app.Activity
 5 | import android.app.AlertDialog
 6 | import android.content.Context
 7 | import android.content.Intent
 8 | import android.net.Uri
 9 | import android.os.Build
10 | import android.os.PowerManager
11 | import android.provider.Settings
12 | import android.view.LayoutInflater
13 | import androidx.databinding.DataBindingUtil
14 | import org.bepass.oblivion.R
15 | import org.bepass.oblivion.databinding.DialogBatteryOptimizationBinding
16 | 
17 | /**
18 |  * Checks if the app is running in restricted background mode.
19 |  * Returns true if running in restricted mode, false otherwise.
20 |  */
21 | fun isBatteryOptimizationEnabled(context: Context): Boolean {
22 |     if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
23 |         val powerManager = context.getSystemService(Context.POWER_SERVICE) as? PowerManager
24 |         return powerManager?.isIgnoringBatteryOptimizations(context.packageName) == false
25 |     }
26 |     return false
27 | }
28 | 
29 | /**
30 |  * Directly requests to ignore battery optimizations for the app.
31 |  */
32 | @SuppressLint("BatteryLife")
33 | fun requestIgnoreBatteryOptimizations(context: Context) {
34 |     if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
35 |         val pm = context.getSystemService(Context.POWER_SERVICE) as PowerManager
36 |         if (!pm.isIgnoringBatteryOptimizations(context.packageName)) {
37 |             val intent = Intent(Settings.ACTION_REQUEST_IGNORE_BATTERY_OPTIMIZATIONS).apply {
38 |                 data = Uri.parse("package:${context.packageName}")
39 |             }
40 |             // Check if context is an Activity
41 |             if (context is Activity) {
42 |                 context.startActivityForResult(intent, 0) // Consider using a valid request code
43 |             } else {
44 |                 intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
45 |                 context.startActivity(intent)
46 |             }
47 |         }
48 |     }
49 | }
50 | 
51 | 
52 | /**
53 |  * Shows a dialog explaining the need for disabling battery optimization and navigates to the app's settings.
54 |  */
55 | fun showBatteryOptimizationDialog(context: Context) {
56 |     // Inflate the dialog layout using Data Binding
57 |     val binding: DialogBatteryOptimizationBinding = DataBindingUtil.inflate(
58 |         LayoutInflater.from(context),
59 |         R.layout.dialog_battery_optimization,
60 |         null,
61 |         false
62 |     )
63 | 
64 |     val dialog = AlertDialog.Builder(context)
65 |         .setView(binding.root)
66 |         .create()
67 | 
68 |     // Set dialog title and message
69 |     binding.dialogTitle.text = context.getString(R.string.batteryOpL)
70 |     binding.dialogMessage.text = context.getString(R.string.dialBtText)
71 | 
72 |     // Set positive button action
73 |     binding.dialogButtonPositive.setOnClickListener {
74 |         requestIgnoreBatteryOptimizations(context)
75 |         dialog.dismiss()
76 |     }
77 | 
78 |     // Set negative button action
79 |     binding.dialogButtonNegative.setOnClickListener {
80 |         dialog.dismiss()
81 |     }
82 | 
83 |     dialog.show()
84 | }
85 | 


--------------------------------------------------------------------------------
/app/src/main/java/org/bepass/oblivion/utils/ColorUtils.java:
--------------------------------------------------------------------------------
 1 | package org.bepass.oblivion.utils;
 2 | 
 3 | import android.graphics.Color;
 4 | 
 5 | public class ColorUtils {
 6 | 
 7 |     public static boolean isColorDark(int color) {
 8 |         double luminance = (0.299 * Color.red(color) + 0.587 * Color.green(color) + 0.114 * Color.blue(color)) / 255;
 9 |         return luminance <= 0.5;
10 |     }
11 | }
12 | 


--------------------------------------------------------------------------------
/app/src/main/java/org/bepass/oblivion/utils/CountryCodeExtensions.kt:
--------------------------------------------------------------------------------
 1 | @file:JvmName("CountryCodeUtils")
 2 | 
 3 | package org.bepass.oblivion.utils
 4 | 
 5 | import java.util.Locale
 6 | 
 7 | fun CountryCode.toCountryFlagEmoji() = value.uppercase()
 8 |     .fold(charArrayOf()) { acc, c ->
 9 |         acc + Character.toChars(c.code + 0x1F1A5)
10 |     }
11 |     .joinToString(separator = "")
12 | 
13 | class CountryCode(val value: String) {
14 |     init {
15 |         require(value in Locale.getISOCountries())
16 |     }
17 | }
18 | 


--------------------------------------------------------------------------------
/app/src/main/java/org/bepass/oblivion/utils/CountryUtils.java:
--------------------------------------------------------------------------------
 1 | package org.bepass.oblivion.utils;
 2 | 
 3 | import android.content.Context;
 4 | import android.content.res.Resources;
 5 | 
 6 | import org.bepass.oblivion.R;
 7 | 
 8 | import java.util.Locale;
 9 | 
10 | import kotlin.Triple;
11 | 
12 | public class CountryUtils {
13 | 
14 |     public static Triple<String, String, Integer> getCountryCode(Context context, String name) {
15 |         Resources resources = context.getResources();
16 | 
17 |         // Retrieve the list of country names in the current locale and the English names
18 |         String[] translatedNames = resources.getStringArray(R.array.countries);
19 |         String[] englishNames = resources.getStringArray(R.array.englishCountries);
20 |         // First, check if the incoming name is in English and find the index directly
21 |         for (int i = 0; i < englishNames.length; i++) {
22 |             if (englishNames[i].equalsIgnoreCase(name)) {
23 |                 // Return the corresponding English name, the original name, and the index
24 |                 String countryCode = getCoCo(name);
25 |                 return new Triple<>(countryCode, englishNames[i], i);
26 |             }
27 |         }
28 | 
29 |         // If not found in English, translate the incoming country name to English
30 |         Triple<String, String, Integer> countryCodeAndName = translateToEnglish(name, translatedNames, englishNames);
31 | 
32 |         // Get the ISO country code using the translated English name
33 |         String countryCode = getCoCo(countryCodeAndName.component1());
34 | 
35 |         // Return the triple of country code, full country name, and index
36 |         return new Triple<>(countryCode, countryCodeAndName.component2(), countryCodeAndName.component3());
37 |     }
38 | 
39 |     private static Triple<String, String, Integer> translateToEnglish(String name, String[] translatedNames, String[] englishNames) {
40 |         for (int i = 0; i < translatedNames.length; i++) {
41 |             if (translatedNames[i].equalsIgnoreCase(name)) {
42 |                 // Return the corresponding English name, the original translated name, and the index
43 |                 return new Triple<>(englishNames[i], translatedNames[i], i);
44 |             }
45 |         }
46 | 
47 |         // If translation not found, return the original name
48 |         return new Triple<>(name, name, 0);
49 |     }
50 | 
51 |     private static String getCoCo(String name) {
52 |         for (String code : Locale.getISOCountries()) {
53 |             Locale locale = new Locale("en", code); // Set the language to English
54 |             if (locale.getDisplayCountry(Locale.ENGLISH).equalsIgnoreCase(name)) {
55 |                 return code;
56 |             }
57 |         }
58 |         return "";
59 |     }
60 | }


--------------------------------------------------------------------------------
/app/src/main/java/org/bepass/oblivion/utils/ISPUtils.kt:
--------------------------------------------------------------------------------
 1 | package org.bepass.oblivion.utils
 2 | 
 3 | import org.json.JSONObject
 4 | import java.io.BufferedReader
 5 | import java.io.InputStreamReader
 6 | import java.net.HttpURLConnection
 7 | import java.net.URL
 8 | 
 9 | object ISPUtils {
10 | 
11 |     private const val API_URL = "http://ip-api.com/json"
12 | 
13 |     // Interface to handle ISP callback
14 |     interface ISPCallback {
15 |         fun onISPInfoReceived(isp: String)
16 |         fun onError(e: Exception)
17 |     }
18 | 
19 |     // Public function to fetch ISP info
20 |     @JvmStatic
21 |     fun fetchISPInfo(callback: ISPCallback) {
22 |         Thread {
23 |             var connection: HttpURLConnection? = null
24 |             var reader: BufferedReader? = null
25 |             try {
26 |                 val url = URL(API_URL)
27 |                 connection = url.openConnection() as HttpURLConnection
28 |                 connection.requestMethod = "GET"
29 | 
30 |                 if (connection.responseCode == HttpURLConnection.HTTP_OK) {
31 |                     reader = BufferedReader(InputStreamReader(connection.inputStream))
32 |                     val result = StringBuilder()
33 |                     var line: String?
34 |                     while (reader.readLine().also { line = it } != null) {
35 |                         result.append(line)
36 |                     }
37 |                     val jsonObject = JSONObject(result.toString())
38 |                     val isp = jsonObject.optString("org", "Unknown ISP")
39 |                     callback.onISPInfoReceived(isp)
40 |                 } else {
41 |                     callback.onError(Exception("Failed to get response. Code: ${connection.responseCode}"))
42 |                 }
43 |             } catch (e: Exception) {
44 |                 callback.onError(e)
45 |             } finally {
46 |                 try {
47 |                     reader?.close()
48 |                     connection?.disconnect()
49 |                 } catch (e: Exception) {
50 |                     callback.onError(e)
51 |                 }
52 |             }
53 |         }.start()
54 |     }
55 | }


--------------------------------------------------------------------------------
/app/src/main/java/org/bepass/oblivion/utils/LocaleHandler.java:
--------------------------------------------------------------------------------
  1 | package org.bepass.oblivion.utils;
  2 | 
  3 | import android.app.AlertDialog;
  4 | import android.content.Context;
  5 | import android.content.res.Resources;
  6 | import android.util.Log;
  7 | 
  8 | import androidx.appcompat.app.AppCompatDelegate;
  9 | import androidx.core.os.LocaleListCompat;
 10 | 
 11 | import com.github.erfansn.localeconfigx.LocaleConfigXKt;
 12 | 
 13 | import org.bepass.oblivion.R;
 14 | 
 15 | import java.util.ArrayList;
 16 | import java.util.Arrays;
 17 | import java.util.List;
 18 | import java.util.Locale;
 19 | 
 20 | public class LocaleHandler {
 21 |     private final Context context;
 22 |     private final LocaleListCompat configuredLocales;
 23 | 
 24 |     private static final String DEFAULT_LOCALE = "fa";
 25 |     private static final String IS_SET_DEFAULT_LOCALE = "is_set_default_locale";
 26 | 
 27 |     // Define a variable to hold allowed languages
 28 |     private final List<String> allowedLanguages;
 29 | 
 30 |     public LocaleHandler(Context context) {
 31 |         this.context = context;
 32 | 
 33 |         // Initialize allowedLanguages from resources
 34 |         this.allowedLanguages = Arrays.asList(context.getResources().getStringArray(R.array.allowed_languages));
 35 | 
 36 |         LocaleListCompat locales;
 37 |         try {
 38 |             // Attempt to get configured locales
 39 |             locales = LocaleConfigXKt.getConfiguredLocales(context);
 40 |             if (locales.isEmpty()) {
 41 |                 throw new Resources.NotFoundException("No locales found");
 42 |             }
 43 |         } catch (Exception e) {
 44 |             // Log error and attempt to load all available locales from resources
 45 |             Log.e("LocaleHandler", "Failed to load locale configuration. Attempting to load all available locales.", e);
 46 |             try {
 47 |                 // Retrieve all available locales from the app's resources
 48 |                 String[] availableLocales = context.getResources().getAssets().getLocales();
 49 |                 String[] validLocales = filterValidLocales(availableLocales);
 50 |                 locales = LocaleListCompat.forLanguageTags(joinLocales(filterAllowedLocales(validLocales)));
 51 |             } catch (Exception ex) {
 52 |                 // Fallback to system locales if loading from resources fails
 53 |                 Log.e("LocaleHandler", "Failed to load available locales from resources. Attempting to use system locales.", ex);
 54 |                 locales = LocaleListCompat.forLanguageTags(joinLocales(filterAllowedLocales(getSystemLocales())));
 55 |             }
 56 |         }
 57 | 
 58 |         this.configuredLocales = locales;
 59 |     }
 60 | 
 61 |     private String[] getSystemLocales() {
 62 |         Locale[] locales = Locale.getAvailableLocales();
 63 |         List<String> localCountries = new ArrayList<>();
 64 |         for (Locale locale : locales) {
 65 |             String languageTag = locale.toLanguageTag();
 66 |             if (!languageTag.isEmpty() && !languageTag.equals("und")) {
 67 |                 localCountries.add(languageTag);
 68 |             }
 69 |         }
 70 |         return localCountries.toArray(new String[0]);
 71 |     }
 72 | 
 73 |     private String[] filterValidLocales(String[] locales) {
 74 |         if (locales == null) {
 75 |             return new String[0];
 76 |         }
 77 | 
 78 |         List<String> validLocales = new ArrayList<>();
 79 |         for (String localeTag : locales) {
 80 |             if (!localeTag.isEmpty() && !localeTag.equals("und")) {
 81 |                 validLocales.add(localeTag);
 82 |             }
 83 |         }
 84 |         return validLocales.toArray(new String[0]);
 85 |     }
 86 | 
 87 |     private String[] filterAllowedLocales(String[] locales) {
 88 |         List<String> filteredLocales = new ArrayList<>();
 89 |         for (String localeTag : locales) {
 90 |             Locale locale = Locale.forLanguageTag(localeTag);
 91 |             if (allowedLanguages.contains(locale.getLanguage())) {
 92 |                 filteredLocales.add(localeTag);
 93 |             }
 94 |         }
 95 |         return filteredLocales.toArray(new String[0]);
 96 |     }
 97 | 
 98 |     private String joinLocales(String[] locales) {
 99 |         StringBuilder joinedLocales = new StringBuilder();
100 |         for (int i = 0; i < locales.length; i++) {
101 |             joinedLocales.append(locales[i]);
102 |             if (i < locales.length - 1) {
103 |                 joinedLocales.append(",");
104 |             }
105 |         }
106 |         return joinedLocales.toString();
107 |     }
108 | 
109 |     public void setPersianAsDefaultLocaleIfNeeds() {
110 |         if (!FileManager.getBoolean(IS_SET_DEFAULT_LOCALE)) {
111 |             Locale persianLocale = Locale.forLanguageTag(DEFAULT_LOCALE);
112 |             AppCompatDelegate.setApplicationLocales(LocaleListCompat.create(persianLocale));
113 |             FileManager.set(IS_SET_DEFAULT_LOCALE, true);
114 |         }
115 |     }
116 | 
117 |     public void showLanguageSelectionDialog() {
118 |         AlertDialog.Builder builder = new AlertDialog.Builder(context);
119 |         builder.setTitle(R.string.select_language)
120 |                 .setItems(getAvailableLanguagesNames(), (dialogInterface, which) -> {
121 |                     Locale selectedLocale = configuredLocales.get(which);
122 |                     LocaleListCompat desiredLocales = LocaleListCompat.create(selectedLocale);
123 |                     AppCompatDelegate.setApplicationLocales(desiredLocales);
124 |                 })
125 |                 .show();
126 |     }
127 | 
128 |     private String[] getAvailableLanguagesNames() {
129 |         String[] languageNames = new String[configuredLocales.size()];
130 |         for (int index = 0; index < configuredLocales.size(); index++) {
131 |             Locale locale = configuredLocales.get(index);
132 |             languageNames[index] = locale != null ? locale.getDisplayName() : "Unknown";
133 |         }
134 |         return languageNames;
135 |     }
136 | }


--------------------------------------------------------------------------------
/app/src/main/java/org/bepass/oblivion/utils/LocaleHelper.java:
--------------------------------------------------------------------------------
 1 | package org.bepass.oblivion.utils;
 2 | 
 3 | import android.content.Context;
 4 | import android.content.res.Configuration;
 5 | import android.content.res.Resources;
 6 | import android.os.Build;
 7 | 
 8 | import org.bepass.oblivion.R;
 9 | 
10 | import java.util.Locale;
11 | 
12 | public class LocaleHelper {
13 |     private static Locale originalLocale;
14 | 
15 |     public static void goEn(Context context) {
16 |         Resources resources = context.getResources();
17 |         Configuration configuration = resources.getConfiguration();
18 |         if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
19 |             originalLocale = configuration.getLocales().get(0); // Save the original locale
20 |         }
21 | 
22 |         // Change locale to English
23 |         configuration.setLocale(new Locale("en"));
24 |         resources.updateConfiguration(configuration, resources.getDisplayMetrics());
25 |     }
26 | 
27 |     public static void restoreLocale(Context context) {
28 |         if (originalLocale != null) {
29 |             Resources resources = context.getResources();
30 |             Configuration configuration = resources.getConfiguration();
31 | 
32 |             // Restore the original locale
33 |             configuration.setLocale(originalLocale);
34 |             resources.updateConfiguration(configuration, resources.getDisplayMetrics());
35 |         }
36 |     }
37 | 
38 |     public static String restoreText(Context context, String text) {
39 |         if (originalLocale != null) {
40 |             Resources resources = context.getResources();
41 |             // Load the English country names
42 |             String[] englishNames = resources.getStringArray(R.array.englishCountries);
43 |             restoreLocale(context);
44 |             // Load the translated country names
45 |             String[] translatedNames = resources.getStringArray(R.array.countries);
46 | 
47 |             // Find the translated name by matching the English name
48 |             for (int i = 0; i < englishNames.length; i++) {
49 |                 if (englishNames[i].equalsIgnoreCase(text)) {
50 |                     return translatedNames[i];
51 |                 }
52 |             }
53 |         }
54 |         return text; // Return the original text if no translation is found or original locale is not set
55 |     }
56 | }


--------------------------------------------------------------------------------
/app/src/main/java/org/bepass/oblivion/utils/NetworkUtils.java:
--------------------------------------------------------------------------------
 1 | package org.bepass.oblivion.utils;
 2 | 
 3 | import static org.bepass.oblivion.service.OblivionVpnService.stopVpnService;
 4 | 
 5 | import android.content.Context;
 6 | import android.net.ConnectivityManager;
 7 | import android.net.Network;
 8 | import android.net.NetworkCapabilities;
 9 | import android.net.NetworkInfo;
10 | import android.net.wifi.WifiManager;
11 | import android.os.Build;
12 | import android.os.Handler;
13 | 
14 | import org.bepass.oblivion.enums.ConnectionState;
15 | 
16 | import java.util.Locale;
17 | 
18 | public class NetworkUtils {
19 | 
20 |     private static final Handler handler = new Handler();
21 |     public static void monitorInternetConnection(ConnectionState lastKnownConnectionState, Context context) {
22 |         handler.postDelayed(new Runnable() {
23 |             @Override
24 |             public void run() {
25 |                 if (!lastKnownConnectionState.isDisconnected()) {
26 |                     checkInternetConnectionAndDisconnectVPN(context);
27 |                     handler.postDelayed(this, 3000); // Check every 3 seconds
28 |                 }
29 |             }
30 |         }, 5000); // Start checking after 5 seconds
31 |     }
32 |     // Periodically check internet connection and disconnect VPN if not connected
33 |     private static void checkInternetConnectionAndDisconnectVPN(Context context) {
34 |         if (!isConnectedToInternet(context)) {
35 |             stopVpnService(context);
36 |         }
37 |     }
38 | 
39 |     private static boolean isConnectedToInternet(Context context) {
40 |         ConnectivityManager connectivityManager = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
41 | 
42 |         if (connectivityManager != null) {
43 |             if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
44 |                 Network activeNetwork = connectivityManager.getActiveNetwork();
45 |                 if (activeNetwork != null) {
46 |                     NetworkCapabilities networkCapabilities = connectivityManager.getNetworkCapabilities(activeNetwork);
47 |                     return networkCapabilities != null &&
48 |                             (networkCapabilities.hasTransport(NetworkCapabilities.TRANSPORT_WIFI) ||
49 |                                     networkCapabilities.hasTransport(NetworkCapabilities.TRANSPORT_CELLULAR));
50 |                 }
51 |             } else {
52 |                 // For API levels below 23, use the deprecated method
53 |                 NetworkInfo activeNetwork = connectivityManager.getActiveNetworkInfo();
54 |                 return activeNetwork != null && activeNetwork.isConnectedOrConnecting();
55 |             }
56 |         }
57 |         return false;
58 |     }
59 |     public static String getLocalIpAddress(Context context) throws Exception {
60 |         ConnectivityManager connectivityManager = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
61 |         NetworkInfo activeNetwork = connectivityManager.getActiveNetworkInfo();
62 | 
63 |         if (activeNetwork != null && activeNetwork.isConnected()) {
64 |             if (activeNetwork.getType() == ConnectivityManager.TYPE_WIFI) {
65 |                 // Get IP Address from Wi-Fi
66 |                 WifiManager wifiManager = (WifiManager) context.getApplicationContext().getSystemService(Context.WIFI_SERVICE);
67 |                 int ipAddress = wifiManager.getConnectionInfo().getIpAddress();
68 |                 return String.format(Locale.US, "%d.%d.%d.%d",
69 |                         (ipAddress & 0xff),
70 |                         (ipAddress >> 8 & 0xff),
71 |                         (ipAddress >> 16 & 0xff),
72 |                         (ipAddress >> 24 & 0xff));
73 |             } else if (activeNetwork.getType() == ConnectivityManager.TYPE_MOBILE) {
74 |                 // Throw exception if connected to Mobile Data (4G)
75 |                 throw new Exception("Operation not allowed on cellular data (4G). Please connect to Wi-Fi.");
76 |             }
77 |         } else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
78 |             NetworkCapabilities capabilities = connectivityManager.getNetworkCapabilities(connectivityManager.getActiveNetwork());
79 |             if (capabilities != null && capabilities.hasTransport(NetworkCapabilities.TRANSPORT_WIFI)) {
80 |                 // Get IP Address from Wi-Fi
81 |                 WifiManager wifiManager = (WifiManager) context.getApplicationContext().getSystemService(Context.WIFI_SERVICE);
82 |                 int ipAddress = wifiManager.getConnectionInfo().getIpAddress();
83 |                 return String.format(Locale.US, "%d.%d.%d.%d",
84 |                         (ipAddress & 0xff),
85 |                         (ipAddress >> 8 & 0xff),
86 |                         (ipAddress >> 16 & 0xff),
87 |                         (ipAddress >> 24 & 0xff));
88 |             } else if (capabilities != null && capabilities.hasTransport(NetworkCapabilities.TRANSPORT_CELLULAR)) {
89 |                 // Throw exception if connected to Mobile Data (4G)
90 |                 throw new Exception("Operation not allowed on cellular data (4G). Please connect to Wi-Fi.");
91 |             }
92 |         }
93 | 
94 |         return null; // Return null if no connection is available
95 |     }
96 | 
97 | 
98 | }
99 | 


--------------------------------------------------------------------------------
/app/src/main/java/org/bepass/oblivion/utils/PublicIPUtils.java:
--------------------------------------------------------------------------------
  1 | package org.bepass.oblivion.utils;
  2 | 
  3 | import android.os.Handler;
  4 | import android.util.Log;
  5 | 
  6 | import org.bepass.oblivion.model.IPDetails;
  7 | import org.json.JSONObject;
  8 | 
  9 | import java.net.InetSocketAddress;
 10 | import java.net.Proxy;
 11 | import java.util.Objects;
 12 | import java.util.concurrent.Executors;
 13 | import java.util.concurrent.ScheduledExecutorService;
 14 | import java.util.concurrent.TimeUnit;
 15 | 
 16 | import okhttp3.OkHttpClient;
 17 | import okhttp3.Request;
 18 | import okhttp3.Response;
 19 | 
 20 | /**
 21 |  * A utility class for fetching public IP details including the country and its flag.
 22 |  */
 23 | public class PublicIPUtils {
 24 |     private static final String TAG = "PublicIPUtils";
 25 |     private static PublicIPUtils instance;
 26 |     private static final int TIMEOUT_SECONDS = 5;
 27 |     private static final int RETRY_DELAY_MILLIS = 1000;
 28 |     private static final int TIMEOUT_MILLIS = 30 * 1000;
 29 |     private final ScheduledExecutorService scheduler;
 30 |     private static final String URL_COUNTRY_API = "https://api.country.is/";
 31 | 
 32 |     /**
 33 |      * Private constructor to enforce singleton pattern.
 34 |      */
 35 |     private PublicIPUtils() {
 36 |         this.scheduler = Executors.newSingleThreadScheduledExecutor();
 37 |     }
 38 | 
 39 |     /**
 40 |      * Public method to get the singleton instance.
 41 |      *
 42 |      * @return The singleton instance of PublicIPUtils.
 43 |      */
 44 |     public static synchronized PublicIPUtils getInstance() {
 45 |         if (instance == null) {
 46 |             instance = new PublicIPUtils();
 47 |         }
 48 |         return instance;
 49 |     }
 50 | 
 51 |     /**
 52 |      * Fetches public IP details including the country and its flag. This method uses a
 53 |      * retry mechanism with a specified timeout to ensure reliable fetching of the IP details.
 54 |      *
 55 |      * @param callback The callback to handle the IP details once fetched.
 56 |      */
 57 |     public void getIPDetails(IPDetailsCallback callback) {
 58 |         Handler handler = new Handler();
 59 |         long startTime = System.currentTimeMillis();
 60 |         IPDetails details = new IPDetails();
 61 | 
 62 |         Log.d(TAG, "Starting getIPDetails process");
 63 | 
 64 |         scheduler.schedule(() -> {
 65 |             while (System.currentTimeMillis() - startTime < TIMEOUT_MILLIS) { // 30 seconds
 66 |                 Log.d(TAG, "Attempting to fetch IP details");
 67 |                 try {
 68 |                     String portString = FileManager.getString("USERSETTING_port");
 69 |                     if (portString == null || portString.isEmpty()) {
 70 |                         throw new IllegalStateException("USERSETTING_port is not set in FileManager");
 71 |                     }
 72 | 
 73 |                     int socksPort = Integer.parseInt(portString);
 74 |                     Proxy proxy = new Proxy(Proxy.Type.SOCKS, new InetSocketAddress("localhost", socksPort));
 75 | 
 76 |                     OkHttpClient client = new OkHttpClient.Builder()
 77 |                             .proxy(proxy)
 78 |                             .connectTimeout(TIMEOUT_SECONDS, TimeUnit.SECONDS) // 5 seconds connection timeout
 79 |                             .readTimeout(TIMEOUT_SECONDS, TimeUnit.SECONDS) // 5 seconds read timeout
 80 |                             .build();
 81 | 
 82 |                     Request request = new Request.Builder()
 83 |                             .url(URL_COUNTRY_API)
 84 |                             .build();
 85 | 
 86 |                     try (Response response = client.newCall(request).execute()) {
 87 |                         if (response.body() != null) {
 88 |                             JSONObject jsonData = new JSONObject(Objects.requireNonNull(response.body()).string());
 89 |                             details.ip = jsonData.getString("ip");
 90 |                             details.country = jsonData.getString("country");
 91 |                             details.flag = CountryCodeUtils.toCountryFlagEmoji(new CountryCode(details.country));
 92 |                             Log.d(TAG, "IP details retrieved successfully");
 93 |                         }
 94 |                         handler.post(() -> callback.onDetailsReceived(details));
 95 |                         return; // Exit the loop if details retrieved
 96 |                     } catch (Exception e) {
 97 |                         Log.e(TAG, "Error parsing the response or setting details", e);
 98 |                     }
 99 |                 } catch (Exception e) {
100 |                     Log.e(TAG, "Error fetching IP details", e);
101 |                 } finally {
102 |                     // Schedule next retry even if an error occurred
103 |                     Log.d(TAG, "Scheduling next retry after delay");
104 |                     scheduler.schedule(() -> getIPDetails(callback), RETRY_DELAY_MILLIS, TimeUnit.MILLISECONDS);
105 |                 }
106 |             }
107 |             Log.d(TAG, "Timeout reached without successful IP details retrieval");
108 |             // Timeout reached, no details retrieved
109 |             handler.post(() -> callback.onDetailsReceived(details));
110 |         }, 0, TimeUnit.MILLISECONDS); // Schedule initial attempt immediately
111 |     }
112 | 
113 |     /**
114 |      * Callback interface for receiving IP details.
115 |      */
116 |     public interface IPDetailsCallback {
117 | 
118 |         /**
119 |          * Called when IP details are received.
120 |          *
121 |          * @param details The IP details.
122 |          */
123 |         void onDetailsReceived(IPDetails details);
124 |     }
125 | }
126 | 


--------------------------------------------------------------------------------
/app/src/main/java/org/bepass/oblivion/utils/SystemUtils.java:
--------------------------------------------------------------------------------
 1 | package org.bepass.oblivion.utils;
 2 | 
 3 | import android.app.Activity;
 4 | import android.content.res.Resources;
 5 | import android.os.Build;
 6 | import android.util.Log;
 7 | import android.view.View;
 8 | import android.view.Window;
 9 | 
10 | import androidx.annotation.RequiresApi;
11 | import androidx.core.content.ContextCompat;
12 | 
13 | public class SystemUtils {
14 | 
15 |     @RequiresApi(api = Build.VERSION_CODES.M)
16 |     public static void setStatusBarColor(Activity activity, int color, boolean isDark) {
17 |         try {
18 |             int statusBarColor = ContextCompat.getColor(activity, color);
19 |             activity.getWindow().setStatusBarColor(statusBarColor);
20 | 
21 |             // Adjust status bar icon color based on theme
22 |             changeStatusBarIconColor(activity, isDark);
23 |         } catch (Resources.NotFoundException e) {
24 |             Log.e("ThemeHelper", "Failed to find color resource for status bar", e);
25 |         }
26 |     }
27 | 
28 |     @RequiresApi(api = Build.VERSION_CODES.M)
29 |     private static void changeStatusBarIconColor(Activity activity, boolean isDark) {
30 |         Window window = activity.getWindow();
31 |         View decorView = window.getDecorView();
32 |         int flags = decorView.getSystemUiVisibility();
33 |         if (isDark) {
34 |             // Make status bar icons dark (e.g., for dark background)
35 |             flags |= View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR;
36 |         } else {
37 |             // Make status bar icons light (e.g., for light background)
38 |             flags &= ~View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR;
39 |         }
40 |         decorView.setSystemUiVisibility(flags);
41 |     }
42 | }
43 | 


--------------------------------------------------------------------------------
/app/src/main/java/org/bepass/oblivion/utils/ThemeHelper.java:
--------------------------------------------------------------------------------
  1 | package org.bepass.oblivion.utils;
  2 | 
  3 | import android.app.Activity;
  4 | import android.content.Context;
  5 | import android.graphics.Color;
  6 | import android.graphics.drawable.Drawable;
  7 | import android.os.Build;
  8 | import android.view.View;
  9 | 
 10 | import androidx.annotation.RequiresApi;
 11 | import androidx.appcompat.app.AppCompatDelegate;
 12 | import androidx.core.content.ContextCompat;
 13 | 
 14 | import org.bepass.oblivion.R;
 15 | 
 16 | public class ThemeHelper {
 17 | 
 18 |     public enum Theme {
 19 |         LIGHT(AppCompatDelegate.MODE_NIGHT_NO),
 20 |         DARK(AppCompatDelegate.MODE_NIGHT_YES),
 21 |         FOLLOW_SYSTEM(AppCompatDelegate.MODE_NIGHT_FOLLOW_SYSTEM),
 22 |         UNSPECIFIED(AppCompatDelegate.MODE_NIGHT_UNSPECIFIED),
 23 |         AUTO_BATTERY(AppCompatDelegate.MODE_NIGHT_AUTO_BATTERY);
 24 | 
 25 |         private final int nightMode;
 26 | 
 27 |         Theme(int nightMode) {
 28 |             this.nightMode = nightMode;
 29 |         }
 30 | 
 31 |         @AppCompatDelegate.NightMode
 32 |         public int getNightMode() {
 33 |             return nightMode;
 34 |         }
 35 | 
 36 |         public static Theme fromNightMode(@AppCompatDelegate.NightMode int nightMode) {
 37 |             for (Theme theme : values()) {
 38 |                 if (theme.getNightMode() == nightMode) {
 39 |                     return theme;
 40 |                 }
 41 |             }
 42 |             return LIGHT; // Default to LIGHT if not found
 43 |         }
 44 |     }
 45 | 
 46 |     private static ThemeHelper instance;
 47 |     private Theme currentTheme = Theme.LIGHT;
 48 | 
 49 |     private ThemeHelper() {
 50 |     }
 51 | 
 52 |     public static synchronized ThemeHelper getInstance() {
 53 |         if (instance == null) {
 54 |             instance = new ThemeHelper();
 55 |         }
 56 |         return instance;
 57 |     }
 58 | 
 59 |     public void init() {
 60 |         int themeMode = FileManager.getInt(FileManager.KeyHolder.DARK_MODE);
 61 |         currentTheme = Theme.fromNightMode(themeMode);
 62 |         applyTheme();
 63 |     }
 64 | 
 65 |     public void applyTheme() {
 66 |         AppCompatDelegate.setDefaultNightMode(currentTheme.getNightMode());
 67 |     }
 68 | 
 69 |     public void select(Theme theme) {
 70 |         currentTheme = theme;
 71 |         FileManager.set(FileManager.KeyHolder.DARK_MODE, theme.nightMode);
 72 |         applyTheme();
 73 |     }
 74 | 
 75 |     public Theme getCurrentTheme() {
 76 |         return currentTheme;
 77 |     }
 78 | 
 79 |     public Drawable getBackgroundDrawable(Context context) {
 80 |         if (currentTheme == Theme.LIGHT) {
 81 |             return ContextCompat.getDrawable(context, R.drawable.background_gradient);
 82 |         } else {
 83 |             return ContextCompat.getDrawable(context, R.color.background);
 84 |         }
 85 |     }
 86 | 
 87 |     public void updateActivityBackground(View view) {
 88 |         // Apply theme-based background
 89 |         Drawable backgroundDrawable = getBackgroundDrawable(view.getContext());
 90 |         if (backgroundDrawable != null) {
 91 |             view.setBackground(backgroundDrawable);
 92 |         }
 93 | 
 94 |         // Configure status bar based on theme
 95 |         if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
 96 |             configureStatusBar(view.getContext() instanceof Activity ? (Activity) view.getContext() : null);
 97 |         }
 98 |     }
 99 |     @RequiresApi(api = Build.VERSION_CODES.M)
100 |     private void configureStatusBar(Activity activity) {
101 |         if (activity == null) return;
102 | 
103 |         activity.getWindow().setStatusBarColor(Color.TRANSPARENT);
104 | 
105 |         // Determine UI visibility flags
106 |         int uiVisibility = View.SYSTEM_UI_FLAG_LAYOUT_STABLE | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN;
107 | 
108 |         if (currentTheme == Theme.LIGHT) {
109 |             // Set dark icons for light theme
110 |             uiVisibility |= View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR;
111 |         }
112 | 
113 |         activity.getWindow().getDecorView().setSystemUiVisibility(uiVisibility);
114 |     }
115 | }


--------------------------------------------------------------------------------
/app/src/main/res/color/checkbox_tint.xml:
--------------------------------------------------------------------------------
1 | <?xml version="1.0" encoding="utf-8"?>
2 | <selector xmlns:android="http://schemas.android.com/apk/res/android">
3 |     <!-- Checked and enabled -->
4 |     <item android:color="@color/primary" android:state_checked="true" android:state_enabled="true"/>
5 |     <!-- Default (disabled) -->
6 |     <item android:color="@color/subtitle_color"/> <!-- This uses the default color -->
7 | </selector>
8 | 


--------------------------------------------------------------------------------
/app/src/main/res/color/tint_selector.xml:
--------------------------------------------------------------------------------
1 | <?xml version="1.0" encoding="utf-8"?>
2 | <selector xmlns:android="http://schemas.android.com/apk/res/android">
3 |     <!-- For Dark theme (use white tint) -->
4 |     <item android:color="@android:color/white" android:state_checked="true" />
5 |     <!-- For Light theme (no tint) -->
6 |     <item android:color="@android:color/transparent" />
7 | </selector>
8 | 


--------------------------------------------------------------------------------
/app/src/main/res/drawable-anydpi/about_item.xml:
--------------------------------------------------------------------------------
1 | <?xml version="1.0" encoding="utf-8"?>
2 | <shape xmlns:android="http://schemas.android.com/apk/res/android"
3 |   android:shape="rectangle">
4 | 
5 |   <solid android:color="#EEEEEE" />
6 |   <corners android:radius="24dp" />
7 | </shape>
8 | 


--------------------------------------------------------------------------------
/app/src/main/res/drawable-anydpi/bottom_sheet_closer.xml:
--------------------------------------------------------------------------------
 1 | <?xml version="1.0" encoding="utf-8"?>
 2 | <layer-list xmlns:android="http://schemas.android.com/apk/res/android">
 3 | 
 4 |   <!-- Soft shadow layer -->
 5 |   <item android:left="2dp" android:right="2dp" android:top="2dp" android:bottom="2dp">
 6 |     <shape android:shape="rectangle">
 7 |       <solid android:color="#80000000" /> <!-- Semi-transparent black -->
 8 |       <corners android:radius="8dp" />
 9 |     </shape>
10 |   </item>
11 | 
12 |   <!-- Actual closer -->
13 |   <item>
14 |     <shape android:shape="rectangle">
15 |       <solid android:color="@color/primary" />
16 |       <corners android:radius="8dp" />
17 |     </shape>
18 |   </item>
19 | 
20 | </layer-list>


--------------------------------------------------------------------------------
/app/src/main/res/drawable-anydpi/edittext_back.xml:
--------------------------------------------------------------------------------
1 | <?xml version="1.0" encoding="utf-8"?>
2 | <shape xmlns:android="http://schemas.android.com/apk/res/android"
3 |   android:shape="rectangle">
4 | 
5 |   <stroke android:color="#A3A3A3" android:width="1dp" />
6 |   <corners android:radius="8dp" />
7 | </shape>
8 | 


--------------------------------------------------------------------------------
/app/src/main/res/drawable-anydpi/ic_back.xml:
--------------------------------------------------------------------------------
 1 | <vector xmlns:android="http://schemas.android.com/apk/res/android"
 2 |   android:width="24dp"
 3 |   android:height="24dp"
 4 |   android:viewportWidth="24"
 5 |   android:viewportHeight="24"
 6 |   android:tint="#5E5E5E"
 7 |   android:alpha="0.6"
 8 |   android:autoMirrored="true">
 9 |   <path
10 |     android:fillColor="@android:color/white"
11 |     android:pathData="M20,11H7.83l5.59,-5.59L12,4l-8,8 8,8 1.41,-1.41L7.83,13H20v-2z" />
12 | </vector>
13 | 


--------------------------------------------------------------------------------
/app/src/main/res/drawable-anydpi/ic_bug.xml:
--------------------------------------------------------------------------------
 1 | <vector xmlns:android="http://schemas.android.com/apk/res/android"
 2 |   android:width="24dp"
 3 |   android:height="24dp"
 4 |   android:viewportWidth="24"
 5 |   android:viewportHeight="24"
 6 |   android:tint="#5E5E5E"
 7 |   android:alpha="0.6">
 8 |   <path
 9 |     android:fillColor="@android:color/white"
10 |     android:pathData="M20,8h-2.81c-0.45,-0.78 -1.07,-1.45 -1.82,-1.96L17,4.41 15.59,3l-2.17,2.17C12.96,5.06 12.49,5 12,5c-0.49,0 -0.96,0.06 -1.41,0.17L8.41,3 7,4.41l1.62,1.63C7.88,6.55 7.26,7.22 6.81,8L4,8v2h2.09c-0.05,0.33 -0.09,0.66 -0.09,1v1L4,12v2h2v1c0,0.34 0.04,0.67 0.09,1L4,16v2h2.81c1.04,1.79 2.97,3 5.19,3s4.15,-1.21 5.19,-3L20,18v-2h-2.09c0.05,-0.33 0.09,-0.66 0.09,-1v-1h2v-2h-2v-1c0,-0.34 -0.04,-0.67 -0.09,-1L20,10L20,8zM14,16h-4v-2h4v2zM14,12h-4v-2h4v2z" />
11 | </vector>
12 | 


--------------------------------------------------------------------------------
/app/src/main/res/drawable-anydpi/ic_info.xml:
--------------------------------------------------------------------------------
 1 | <vector xmlns:android="http://schemas.android.com/apk/res/android"
 2 |   android:width="24dp"
 3 |   android:height="24dp"
 4 |   android:viewportWidth="24"
 5 |   android:viewportHeight="24"
 6 |   android:tint="#5E5E5E"
 7 |   android:alpha="0.6">
 8 |   <path
 9 |     android:fillColor="@android:color/white"
10 |     android:pathData="M12,2C6.48,2 2,6.48 2,12s4.48,10 10,10 10,-4.48 10,-10S17.52,2 12,2zM13,17h-2v-6h2v6zM13,9h-2L11,7h2v2z" />
11 | </vector>
12 | 


--------------------------------------------------------------------------------
/app/src/main/res/drawable-anydpi/ic_power.xml:
--------------------------------------------------------------------------------
 1 | <vector xmlns:android="http://schemas.android.com/apk/res/android"
 2 |   android:width="24dp"
 3 |   android:height="24dp"
 4 |   android:viewportWidth="24"
 5 |   android:viewportHeight="24"
 6 |   android:tint="#5E5E5E"
 7 |   android:alpha="0.6">
 8 |   <path
 9 |     android:fillColor="@android:color/white"
10 |     android:pathData="M13,3h-2v10h2L13,3zM17.83,5.17l-1.42,1.42C17.99,7.86 19,9.81 19,12c0,3.87 -3.13,7 -7,7s-7,-3.13 -7,-7c0,-2.19 1.01,-4.14 2.58,-5.42L6.17,5.17C4.23,6.82 3,9.26 3,12c0,4.97 4.03,9 9,9s9,-4.03 9,-9c0,-2.74 -1.23,-5.18 -3.17,-6.83z" />
11 | </vector>
12 | 


--------------------------------------------------------------------------------
/app/src/main/res/drawable-anydpi/ic_settings.xml:
--------------------------------------------------------------------------------
 1 | <vector xmlns:android="http://schemas.android.com/apk/res/android"
 2 |   android:width="24dp"
 3 |   android:height="24dp"
 4 |   android:viewportWidth="24"
 5 |   android:viewportHeight="24"
 6 |   android:tint="#5E5E5E"
 7 |   android:alpha="0.6">
 8 |   <path
 9 |     android:fillColor="@android:color/white"
10 |     android:pathData="M19.14,12.94c0.04,-0.3 0.06,-0.61 0.06,-0.94c0,-0.32 -0.02,-0.64 -0.07,-0.94l2.03,-1.58c0.18,-0.14 0.23,-0.41 0.12,-0.61l-1.92,-3.32c-0.12,-0.22 -0.37,-0.29 -0.59,-0.22l-2.39,0.96c-0.5,-0.38 -1.03,-0.7 -1.62,-0.94L14.4,2.81c-0.04,-0.24 -0.24,-0.41 -0.48,-0.41h-3.84c-0.24,0 -0.43,0.17 -0.47,0.41L9.25,5.35C8.66,5.59 8.12,5.92 7.63,6.29L5.24,5.33c-0.22,-0.08 -0.47,0 -0.59,0.22L2.74,8.87C2.62,9.08 2.66,9.34 2.86,9.48l2.03,1.58C4.84,11.36 4.8,11.69 4.8,12s0.02,0.64 0.07,0.94l-2.03,1.58c-0.18,0.14 -0.23,0.41 -0.12,0.61l1.92,3.32c0.12,0.22 0.37,0.29 0.59,0.22l2.39,-0.96c0.5,0.38 1.03,0.7 1.62,0.94l0.36,2.54c0.05,0.24 0.24,0.41 0.48,0.41h3.84c0.24,0 0.44,-0.17 0.47,-0.41l0.36,-2.54c0.59,-0.24 1.13,-0.56 1.62,-0.94l2.39,0.96c0.22,0.08 0.47,0 0.59,-0.22l1.92,-3.32c0.12,-0.22 0.07,-0.47 -0.12,-0.61L19.14,12.94zM12,15.6c-1.98,0 -3.6,-1.62 -3.6,-3.6s1.62,-3.6 3.6,-3.6s3.6,1.62 3.6,3.6S13.98,15.6 12,15.6z" />
11 | </vector>
12 | 


--------------------------------------------------------------------------------
/app/src/main/res/drawable-hdpi/ic_back.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bepass-org/oblivion/2ed61afd06003949a59f0bfec7281cfb80814e1e/app/src/main/res/drawable-hdpi/ic_back.png


--------------------------------------------------------------------------------
/app/src/main/res/drawable-hdpi/ic_bug.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bepass-org/oblivion/2ed61afd06003949a59f0bfec7281cfb80814e1e/app/src/main/res/drawable-hdpi/ic_bug.png


--------------------------------------------------------------------------------
/app/src/main/res/drawable-hdpi/ic_github.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bepass-org/oblivion/2ed61afd06003949a59f0bfec7281cfb80814e1e/app/src/main/res/drawable-hdpi/ic_github.png


--------------------------------------------------------------------------------
/app/src/main/res/drawable-hdpi/ic_info.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bepass-org/oblivion/2ed61afd06003949a59f0bfec7281cfb80814e1e/app/src/main/res/drawable-hdpi/ic_info.png


--------------------------------------------------------------------------------
/app/src/main/res/drawable-hdpi/ic_settings.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bepass-org/oblivion/2ed61afd06003949a59f0bfec7281cfb80814e1e/app/src/main/res/drawable-hdpi/ic_settings.png


--------------------------------------------------------------------------------
/app/src/main/res/drawable-hdpi/ic_translate.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bepass-org/oblivion/2ed61afd06003949a59f0bfec7281cfb80814e1e/app/src/main/res/drawable-hdpi/ic_translate.png


--------------------------------------------------------------------------------
/app/src/main/res/drawable-hdpi/rounded_bottom_sheet.xml:
--------------------------------------------------------------------------------
1 | <?xml version="1.0" encoding="utf-8"?>
2 | <shape xmlns:android="http://schemas.android.com/apk/res/android"
3 |   android:shape="rectangle">
4 |   <solid android:color="@color/white" />
5 |   <corners
6 |     android:topLeftRadius="24dp"
7 |     android:topRightRadius="24dp" />
8 | </shape>
9 | 


--------------------------------------------------------------------------------
/app/src/main/res/drawable-mdpi/ic_back.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bepass-org/oblivion/2ed61afd06003949a59f0bfec7281cfb80814e1e/app/src/main/res/drawable-mdpi/ic_back.png


--------------------------------------------------------------------------------
/app/src/main/res/drawable-mdpi/ic_bug.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bepass-org/oblivion/2ed61afd06003949a59f0bfec7281cfb80814e1e/app/src/main/res/drawable-mdpi/ic_bug.png


--------------------------------------------------------------------------------
/app/src/main/res/drawable-mdpi/ic_github.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bepass-org/oblivion/2ed61afd06003949a59f0bfec7281cfb80814e1e/app/src/main/res/drawable-mdpi/ic_github.png


--------------------------------------------------------------------------------
/app/src/main/res/drawable-mdpi/ic_info.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bepass-org/oblivion/2ed61afd06003949a59f0bfec7281cfb80814e1e/app/src/main/res/drawable-mdpi/ic_info.png


--------------------------------------------------------------------------------
/app/src/main/res/drawable-mdpi/ic_ircf.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bepass-org/oblivion/2ed61afd06003949a59f0bfec7281cfb80814e1e/app/src/main/res/drawable-mdpi/ic_ircf.png


--------------------------------------------------------------------------------
/app/src/main/res/drawable-mdpi/ic_power.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bepass-org/oblivion/2ed61afd06003949a59f0bfec7281cfb80814e1e/app/src/main/res/drawable-mdpi/ic_power.png


--------------------------------------------------------------------------------
/app/src/main/res/drawable-mdpi/ic_settings.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bepass-org/oblivion/2ed61afd06003949a59f0bfec7281cfb80814e1e/app/src/main/res/drawable-mdpi/ic_settings.png


--------------------------------------------------------------------------------
/app/src/main/res/drawable-mdpi/ic_translate.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bepass-org/oblivion/2ed61afd06003949a59f0bfec7281cfb80814e1e/app/src/main/res/drawable-mdpi/ic_translate.png


--------------------------------------------------------------------------------
/app/src/main/res/drawable-mdpi/ic_twitter.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bepass-org/oblivion/2ed61afd06003949a59f0bfec7281cfb80814e1e/app/src/main/res/drawable-mdpi/ic_twitter.png


--------------------------------------------------------------------------------
/app/src/main/res/drawable-xhdpi/ic_back.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bepass-org/oblivion/2ed61afd06003949a59f0bfec7281cfb80814e1e/app/src/main/res/drawable-xhdpi/ic_back.png


--------------------------------------------------------------------------------
/app/src/main/res/drawable-xhdpi/ic_bug.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bepass-org/oblivion/2ed61afd06003949a59f0bfec7281cfb80814e1e/app/src/main/res/drawable-xhdpi/ic_bug.png


--------------------------------------------------------------------------------
/app/src/main/res/drawable-xhdpi/ic_github.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bepass-org/oblivion/2ed61afd06003949a59f0bfec7281cfb80814e1e/app/src/main/res/drawable-xhdpi/ic_github.png


--------------------------------------------------------------------------------
/app/src/main/res/drawable-xhdpi/ic_info.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bepass-org/oblivion/2ed61afd06003949a59f0bfec7281cfb80814e1e/app/src/main/res/drawable-xhdpi/ic_info.png


--------------------------------------------------------------------------------
/app/src/main/res/drawable-xhdpi/ic_ircf.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bepass-org/oblivion/2ed61afd06003949a59f0bfec7281cfb80814e1e/app/src/main/res/drawable-xhdpi/ic_ircf.png


--------------------------------------------------------------------------------
/app/src/main/res/drawable-xhdpi/ic_power.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bepass-org/oblivion/2ed61afd06003949a59f0bfec7281cfb80814e1e/app/src/main/res/drawable-xhdpi/ic_power.png


--------------------------------------------------------------------------------
/app/src/main/res/drawable-xhdpi/ic_settings.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bepass-org/oblivion/2ed61afd06003949a59f0bfec7281cfb80814e1e/app/src/main/res/drawable-xhdpi/ic_settings.png


--------------------------------------------------------------------------------
/app/src/main/res/drawable-xhdpi/ic_translate.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bepass-org/oblivion/2ed61afd06003949a59f0bfec7281cfb80814e1e/app/src/main/res/drawable-xhdpi/ic_translate.png


--------------------------------------------------------------------------------
/app/src/main/res/drawable-xhdpi/ic_twitter.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bepass-org/oblivion/2ed61afd06003949a59f0bfec7281cfb80814e1e/app/src/main/res/drawable-xhdpi/ic_twitter.png


--------------------------------------------------------------------------------
/app/src/main/res/drawable-xxhdpi/ic_back.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bepass-org/oblivion/2ed61afd06003949a59f0bfec7281cfb80814e1e/app/src/main/res/drawable-xxhdpi/ic_back.png


--------------------------------------------------------------------------------
/app/src/main/res/drawable-xxhdpi/ic_bug.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bepass-org/oblivion/2ed61afd06003949a59f0bfec7281cfb80814e1e/app/src/main/res/drawable-xxhdpi/ic_bug.png


--------------------------------------------------------------------------------
/app/src/main/res/drawable-xxhdpi/ic_github.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bepass-org/oblivion/2ed61afd06003949a59f0bfec7281cfb80814e1e/app/src/main/res/drawable-xxhdpi/ic_github.png


--------------------------------------------------------------------------------
/app/src/main/res/drawable-xxhdpi/ic_info.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bepass-org/oblivion/2ed61afd06003949a59f0bfec7281cfb80814e1e/app/src/main/res/drawable-xxhdpi/ic_info.png


--------------------------------------------------------------------------------
/app/src/main/res/drawable-xxhdpi/ic_ircf.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bepass-org/oblivion/2ed61afd06003949a59f0bfec7281cfb80814e1e/app/src/main/res/drawable-xxhdpi/ic_ircf.png


--------------------------------------------------------------------------------
/app/src/main/res/drawable-xxhdpi/ic_power.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bepass-org/oblivion/2ed61afd06003949a59f0bfec7281cfb80814e1e/app/src/main/res/drawable-xxhdpi/ic_power.png


--------------------------------------------------------------------------------
/app/src/main/res/drawable-xxhdpi/ic_settings.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bepass-org/oblivion/2ed61afd06003949a59f0bfec7281cfb80814e1e/app/src/main/res/drawable-xxhdpi/ic_settings.png


--------------------------------------------------------------------------------
/app/src/main/res/drawable-xxhdpi/ic_translate.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bepass-org/oblivion/2ed61afd06003949a59f0bfec7281cfb80814e1e/app/src/main/res/drawable-xxhdpi/ic_translate.png


--------------------------------------------------------------------------------
/app/src/main/res/drawable-xxhdpi/ic_twitter.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bepass-org/oblivion/2ed61afd06003949a59f0bfec7281cfb80814e1e/app/src/main/res/drawable-xxhdpi/ic_twitter.png


--------------------------------------------------------------------------------
/app/src/main/res/drawable-xxxhdpi/ic_github.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bepass-org/oblivion/2ed61afd06003949a59f0bfec7281cfb80814e1e/app/src/main/res/drawable-xxxhdpi/ic_github.png


--------------------------------------------------------------------------------
/app/src/main/res/drawable-xxxhdpi/ic_ircf.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bepass-org/oblivion/2ed61afd06003949a59f0bfec7281cfb80814e1e/app/src/main/res/drawable-xxxhdpi/ic_ircf.png


--------------------------------------------------------------------------------
/app/src/main/res/drawable-xxxhdpi/ic_translate.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bepass-org/oblivion/2ed61afd06003949a59f0bfec7281cfb80814e1e/app/src/main/res/drawable-xxxhdpi/ic_translate.png


--------------------------------------------------------------------------------
/app/src/main/res/drawable-xxxhdpi/ic_twitter.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bepass-org/oblivion/2ed61afd06003949a59f0bfec7281cfb80814e1e/app/src/main/res/drawable-xxxhdpi/ic_twitter.png


--------------------------------------------------------------------------------
/app/src/main/res/drawable/background_gradient.xml:
--------------------------------------------------------------------------------
 1 | <?xml version="1.0" encoding="utf-8"?>
 2 | <shape xmlns:android="http://schemas.android.com/apk/res/android"
 3 |   android:shape="rectangle">
 4 |   <gradient
 5 |     android:angle="90"
 6 |     android:endColor="#FCF6D4"
 7 |     android:centerColor="#FFFFFF"
 8 |     android:startColor="#FFFFFF" />
 9 | </shape>
10 | 


--------------------------------------------------------------------------------
/app/src/main/res/drawable/bottom_sheet_cancel.xml:
--------------------------------------------------------------------------------
1 | <?xml version="1.0" encoding="utf-8"?>
2 | <shape xmlns:android="http://schemas.android.com/apk/res/android"
3 |   android:shape="rectangle">
4 | 
5 |   <stroke android:color="@color/black" android:width="1dp" />
6 |   <corners android:radius="8dp" />
7 | </shape>
8 | 


--------------------------------------------------------------------------------
/app/src/main/res/drawable/button.xml:
--------------------------------------------------------------------------------
 1 | <?xml version="1.0" encoding="utf-8"?>
 2 | <layer-list xmlns:android="http://schemas.android.com/apk/res/android">
 3 | 
 4 |     <!-- Shadow -->
 5 |     <item>
 6 |         <shape>
 7 |             <solid android:color="@color/primary" />
 8 |             <corners android:topLeftRadius="6dp" android:topRightRadius="6dp"  />
 9 |         </shape>
10 |     </item>
11 | 
12 |     <!-- Actual Button Background -->
13 |     <item android:top="2dp" android:left="2dp" android:right="2dp" android:bottom="2dp">
14 |         <shape>
15 |             <solid android:color="@color/primary" />
16 |             <corners android:topLeftRadius="6dp" android:topRightRadius="6dp" />
17 |         </shape>
18 |     </item>
19 | 
20 | </layer-list>


--------------------------------------------------------------------------------
/app/src/main/res/drawable/button_op.xml:
--------------------------------------------------------------------------------
 1 | <?xml version="1.0" encoding="utf-8"?>
 2 | <layer-list xmlns:android="http://schemas.android.com/apk/res/android">
 3 | 
 4 |     <!-- Shadow -->
 5 |     <item>
 6 |         <shape>
 7 |             <solid android:color="@color/primary" />
 8 |             <corners android:bottomLeftRadius="6dp" android:bottomRightRadius="6dp"  />
 9 |         </shape>
10 |     </item>
11 | 
12 |     <!-- Actual Button Background -->
13 |     <item android:top="2dp" android:left="2dp" android:right="2dp" android:bottom="2dp">
14 |         <shape>
15 |             <solid android:color="@color/primary" />
16 |             <corners android:bottomLeftRadius="6dp" android:bottomRightRadius="6dp" />
17 |         </shape>
18 |     </item>
19 | 
20 | </layer-list>


--------------------------------------------------------------------------------
/app/src/main/res/drawable/check.xml:
--------------------------------------------------------------------------------
1 | <vector xmlns:android="http://schemas.android.com/apk/res/android" android:height="24dp" android:viewportHeight="960" android:viewportWidth="960" android:width="24dp">
2 |       
3 |     <path android:fillColor="#5f6368" android:pathData="M382,720 L154,492l57,-57 171,171 367,-367 57,57 -424,424Z"/>
4 |     
5 | </vector>
6 | 


--------------------------------------------------------------------------------
/app/src/main/res/drawable/custom_progress_drawable.xml:
--------------------------------------------------------------------------------
 1 | <?xml version="1.0" encoding="utf-8"?>
 2 | <layer-list xmlns:android="http://schemas.android.com/apk/res/android">
 3 |     <!-- Background Circle -->
 4 |     <item>
 5 |         <shape android:shape="oval">
 6 |             <solid android:color="@android:color/transparent"/>
 7 |             <size android:width="40dp" android:height="40dp"/>
 8 |         </shape>
 9 |     </item>
10 | 
11 |     <!-- Rotating Circle -->
12 |     <item>
13 |         <rotate
14 |             android:fromDegrees="0"
15 |             android:toDegrees="360"
16 |             android:pivotX="50%"
17 |             android:pivotY="50%">
18 |             <shape android:shape="oval">
19 |                 <solid android:color="@color/primary"/>
20 |                 <size android:width="24dp" android:height="24dp"/>
21 |                 <corners android:radius="12dp"/>
22 |             </shape>
23 |         </rotate>
24 |     </item>
25 | </layer-list>


--------------------------------------------------------------------------------
/app/src/main/res/drawable/endpoint_sheet.xml:
--------------------------------------------------------------------------------
1 | <?xml version="1.0" encoding="utf-8"?>
2 | <shape xmlns:android="http://schemas.android.com/apk/res/android"
3 |     android:shape="rectangle">
4 |     <solid android:color="@color/background" />
5 |     <corners android:topLeftRadius="30dp" android:topRightRadius="30dp" />
6 | </shape>
7 | 


--------------------------------------------------------------------------------
/app/src/main/res/drawable/expand_up.xml:
--------------------------------------------------------------------------------
 1 | <vector xmlns:android="http://schemas.android.com/apk/res/android"
 2 |     android:width="24dp"
 3 |     android:height="24dp"
 4 |     android:viewportWidth="960"
 5 |     android:viewportHeight="960">
 6 |   <path
 7 |       android:pathData="M480,432 L296,616l-56,-56 240,-240 240,240 -56,56 -184,-184Z"
 8 |       android:fillColor="#5f6368"/>
 9 | </vector>
10 | 


--------------------------------------------------------------------------------
/app/src/main/res/drawable/light_shadow_bottom.xml:
--------------------------------------------------------------------------------
 1 | <?xml version="1.0" encoding="utf-8"?>
 2 | 
 3 | <shape xmlns:android="http://schemas.android.com/apk/res/android"
 4 |     android:shape="rectangle">
 5 |     <gradient
 6 |         android:startColor="@android:color/transparent"
 7 |         android:centerColor="@android:color/transparent"
 8 |         android:endColor="#BEFFFFFF"
 9 |         android:angle="270"/>
10 | </shape>


--------------------------------------------------------------------------------
/app/src/main/res/drawable/segaro.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bepass-org/oblivion/2ed61afd06003949a59f0bfec7281cfb80814e1e/app/src/main/res/drawable/segaro.png


--------------------------------------------------------------------------------
/app/src/main/res/drawable/switch_ripple.xml:
--------------------------------------------------------------------------------
 1 | <?xml version="1.0" encoding="utf-8"?>
 2 | <ripple xmlns:android="http://schemas.android.com/apk/res/android"
 3 |     android:color="?android:attr/colorControlHighlight">
 4 |     <item android:id="@android:id/mask">
 5 |         <shape android:shape="rectangle">
 6 |             <solid android:color="#000000" />
 7 |             <corners android:radius="40dp" />
 8 |         </shape>
 9 |     </item>
10 | </ripple>
11 | 


--------------------------------------------------------------------------------
/app/src/main/res/drawable/toast_background.xml:
--------------------------------------------------------------------------------
1 | <?xml version="1.0" encoding="utf-8"?>
2 | <shape xmlns:android="http://schemas.android.com/apk/res/android">
3 |     <solid android:color="@color/black" />
4 |     <corners android:radius="8dp" />
5 |     <padding android:left="8dp" android:top="8dp" android:right="8dp" android:bottom="8dp" />
6 | </shape>
7 | 


--------------------------------------------------------------------------------
/app/src/main/res/drawable/vpn_off.xml:
--------------------------------------------------------------------------------
1 | <vector android:height="24dp" android:tint="#000000"
2 |   android:viewportHeight="24" android:viewportWidth="24"
3 |   android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
4 |   <path android:fillColor="@android:color/white"
5 |     android:pathData="M20.83,18H21v-4h2v-4H12.83L20.83,18zM19.78,22.61l1.41,-1.41L2.81,2.81L1.39,4.22l2.59,2.59C2.2,7.85 1,9.79 1,12c0,3.31 2.69,6 6,6c2.21,0 4.15,-1.2 5.18,-2.99L19.78,22.61zM8.99,11.82C9,11.88 9,11.94 9,12c0,1.1 -0.9,2 -2,2s-2,-0.9 -2,-2s0.9,-2 2,-2c0.06,0 0.12,0 0.18,0.01L8.99,11.82z" />
6 | </vector>
7 | 


--------------------------------------------------------------------------------
/app/src/main/res/drawable/vpn_on.xml:
--------------------------------------------------------------------------------
1 | <vector android:height="24dp" android:tint="#000000"
2 |   android:viewportHeight="24" android:viewportWidth="24"
3 |   android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
4 |   <path android:fillColor="@android:color/white"
5 |     android:pathData="M12.65,10C11.83,7.67 9.61,6 7,6c-3.31,0 -6,2.69 -6,6s2.69,6 6,6c2.61,0 4.83,-1.67 5.65,-4H17v4h4v-4h2v-4H12.65zM7,14c-1.1,0 -2,-0.9 -2,-2s0.9,-2 2,-2 2,0.9 2,2 -0.9,2 -2,2z" />
6 | </vector>
7 | 


--------------------------------------------------------------------------------
/app/src/main/res/drawable/yousef.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bepass-org/oblivion/2ed61afd06003949a59f0bfec7281cfb80814e1e/app/src/main/res/drawable/yousef.png


--------------------------------------------------------------------------------
/app/src/main/res/font/emoji.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bepass-org/oblivion/2ed61afd06003949a59f0bfec7281cfb80814e1e/app/src/main/res/font/emoji.ttf


--------------------------------------------------------------------------------
/app/src/main/res/font/oxygenbold.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bepass-org/oblivion/2ed61afd06003949a59f0bfec7281cfb80814e1e/app/src/main/res/font/oxygenbold.ttf


--------------------------------------------------------------------------------
/app/src/main/res/font/oxygenlight.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bepass-org/oblivion/2ed61afd06003949a59f0bfec7281cfb80814e1e/app/src/main/res/font/oxygenlight.ttf


--------------------------------------------------------------------------------
/app/src/main/res/font/oxygenregular.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bepass-org/oblivion/2ed61afd06003949a59f0bfec7281cfb80814e1e/app/src/main/res/font/oxygenregular.ttf


--------------------------------------------------------------------------------
/app/src/main/res/font/shabnam.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bepass-org/oblivion/2ed61afd06003949a59f0bfec7281cfb80814e1e/app/src/main/res/font/shabnam.ttf


--------------------------------------------------------------------------------
/app/src/main/res/font/shabnambold.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bepass-org/oblivion/2ed61afd06003949a59f0bfec7281cfb80814e1e/app/src/main/res/font/shabnambold.ttf


--------------------------------------------------------------------------------
/app/src/main/res/font/shabnamlight.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bepass-org/oblivion/2ed61afd06003949a59f0bfec7281cfb80814e1e/app/src/main/res/font/shabnamlight.ttf


--------------------------------------------------------------------------------
/app/src/main/res/font/shabnammedium.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bepass-org/oblivion/2ed61afd06003949a59f0bfec7281cfb80814e1e/app/src/main/res/font/shabnammedium.ttf


--------------------------------------------------------------------------------
/app/src/main/res/font/shabnamthin.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bepass-org/oblivion/2ed61afd06003949a59f0bfec7281cfb80814e1e/app/src/main/res/font/shabnamthin.ttf


--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_info.xml:
--------------------------------------------------------------------------------
  1 | <?xml version="1.0" encoding="utf-8"?>
  2 | <layout xmlns:android="http://schemas.android.com/apk/res/android"
  3 |     xmlns:app="http://schemas.android.com/apk/res-auto"
  4 |     xmlns:tools="http://schemas.android.com/tools">
  5 | 
  6 |   <data>
  7 | 
  8 |   </data>
  9 | 
 10 |   <LinearLayout
 11 |       android:layout_width="match_parent"
 12 |       android:layout_height="match_parent"
 13 |       android:background="@color/background"
 14 |       android:orientation="vertical"
 15 |       tools:context="org.bepass.oblivion.ui.InfoActivity"
 16 |       android:fitsSystemWindows="true">
 17 | 
 18 |     <RelativeLayout
 19 |         android:id="@+id/top_bar"
 20 |         android:layout_width="match_parent"
 21 |         android:layout_height="48dp"
 22 |         android:layout_marginTop="8dp">
 23 | 
 24 |       <org.bepass.oblivion.component.Icon
 25 |           android:id="@+id/back"
 26 |           android:layout_width="35dp"
 27 |           android:layout_height="35dp"
 28 |           android:background="?selectableItemBackgroundBorderless"
 29 |           android:layout_alignParentStart="true"
 30 |           android:layout_centerVertical="true"
 31 |           android:layout_marginStart="16dp"
 32 |           android:contentDescription="back"
 33 |           android:src="@drawable/ic_back"
 34 |           app:icon_color="@color/icon_color"
 35 |           app:tint="@color/icon_color"
 36 |           android:focusable="true"/>
 37 | 
 38 |       <TextView
 39 |           android:layout_width="wrap_content"
 40 |           android:layout_height="wrap_content"
 41 |           android:layout_alignParentEnd="true"
 42 |           android:layout_centerVertical="true"
 43 |           android:layout_marginEnd="16dp"
 44 |           android:fontFamily="@font/shabnamlight"
 45 |           android:text="@string/aboutApp"
 46 |           android:textColor="@color/text_color"
 47 |           android:textSize="32dp"
 48 |           tools:ignore="RelativeOverlap" />
 49 | 
 50 |     </RelativeLayout>
 51 | 
 52 |     <androidx.constraintlayout.widget.ConstraintLayout
 53 |         android:layout_width="match_parent"
 54 |         android:layout_height="wrap_content"
 55 |         android:layout_marginTop="16dp"
 56 |         android:paddingHorizontal="12dp">
 57 | 
 58 |       <TextView
 59 |           android:id="@+id/about"
 60 |           android:layout_width="0dp"
 61 |           android:layout_height="wrap_content"
 62 |           android:fontFamily="@font/shabnammedium"
 63 |           android:text='@string/aboutAppDesc'
 64 |           android:textAlignment="center"
 65 |           android:textColor="@color/subtitle_color"
 66 |           android:textSize="16dp"
 67 |           tools:ignore="RtlCompat"
 68 |           android:focusable="true"
 69 |           app:layout_constraintLeft_toLeftOf="parent"
 70 |           app:layout_constraintRight_toRightOf="parent"
 71 |           app:layout_constraintTop_toTopOf="parent"
 72 |           app:layout_constraintBottom_toBottomOf="parent"
 73 |           android:layout_margin="16dp"/>
 74 | 
 75 |     </androidx.constraintlayout.widget.ConstraintLayout>
 76 | 
 77 |     <RelativeLayout
 78 |         android:id="@+id/github_layout"
 79 |         android:layout_width="match_parent"
 80 |         android:layout_height="wrap_content"
 81 |         android:layout_marginHorizontal="16dp"
 82 |         android:layout_marginTop="32dp"
 83 |         android:background="@drawable/about_item"
 84 |         android:gravity="center"
 85 |         android:paddingVertical="8dp"
 86 |         android:focusable="true">
 87 | 
 88 |       <ImageView
 89 |           android:id="@+id/github_image"
 90 |           android:layout_width="wrap_content"
 91 |           android:layout_height="wrap_content"
 92 |           android:layout_alignParentStart="true"
 93 |           android:layout_centerVertical="true"
 94 |           android:layout_marginStart="8dp"
 95 |           android:layout_marginEnd="8dp"
 96 |           android:src="@drawable/ic_github"
 97 |           app:tint="@color/black"
 98 |           android:focusable="true"/>
 99 | 
100 |       <TextView
101 |           android:layout_width="wrap_content"
102 |           android:layout_height="wrap_content"
103 |           android:layout_centerInParent="true"
104 |           android:layout_toEndOf="@id/github_image"
105 |           android:fontFamily="@font/shabnam"
106 |           android:text="Github"
107 |           android:textColor="@color/black"
108 |           android:textSize="14dp" />
109 | 
110 |       <TextView
111 |           android:layout_width="wrap_content"
112 |           android:layout_height="wrap_content"
113 |           android:layout_alignParentEnd="true"
114 |           android:layout_centerVertical="true"
115 |           android:layout_marginEnd="16dp"
116 |           android:fontFamily="@font/shabnambold"
117 |           android:text="Bepass/Oblivion"
118 |           android:textColor="@color/black"
119 |           android:textSize="14dp" />
120 | 
121 |     </RelativeLayout>
122 | 
123 |     <TextView
124 |         android:layout_width="match_parent"
125 |         android:layout_height="wrap_content"
126 |         android:layout_marginTop="8dp"
127 |         android:fontFamily="@font/shabnam"
128 |         android:gravity="center"
129 |         android:text="@string/appVersion"
130 |         android:textColor="@color/subtitle_color"
131 |         android:textSize="14dp" />
132 | 
133 |   </LinearLayout>
134 | </layout>
135 | 


--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_log.xml:
--------------------------------------------------------------------------------
  1 | <?xml version="1.0" encoding="utf-8"?>
  2 | <layout xmlns:android="http://schemas.android.com/apk/res/android"
  3 |     xmlns:app="http://schemas.android.com/apk/res-auto"
  4 |     xmlns:tools="http://schemas.android.com/tools">
  5 | 
  6 |   <data>
  7 | 
  8 |   </data>
  9 | 
 10 |   <androidx.constraintlayout.widget.ConstraintLayout
 11 |       android:layout_width="match_parent"
 12 |       android:layout_height="match_parent"
 13 |       android:background="@color/background"
 14 |       tools:context="org.bepass.oblivion.ui.LogActivity"
 15 |       android:fitsSystemWindows="true">
 16 | 
 17 |     <RelativeLayout
 18 |         android:id="@+id/top_bar"
 19 |         android:layout_width="match_parent"
 20 |         android:layout_height="48dp"
 21 |         android:layout_marginTop="8dp"
 22 |         app:layout_constraintEnd_toEndOf="parent"
 23 |         app:layout_constraintStart_toStartOf="parent"
 24 |         app:layout_constraintTop_toTopOf="parent">
 25 | 
 26 |       <org.bepass.oblivion.component.Icon
 27 |           android:id="@+id/back"
 28 |           android:layout_width="35dp"
 29 |           android:layout_height="35dp"
 30 |           android:background="?selectableItemBackgroundBorderless"
 31 |           android:layout_alignParentStart="true"
 32 |           android:layout_centerVertical="true"
 33 |           android:layout_marginStart="16dp"
 34 |           app:icon_color="@color/icon_color"
 35 |           android:src="@drawable/ic_back"
 36 |           android:focusable="true"
 37 |           android:nextFocusDown="@id/logScrollView" />
 38 | 
 39 |       <TextView
 40 |           android:layout_width="wrap_content"
 41 |           android:layout_height="wrap_content"
 42 |           android:layout_alignParentEnd="true"
 43 |           android:layout_centerVertical="true"
 44 |           android:layout_marginEnd="16dp"
 45 |           android:fontFamily="@font/shabnamlight"
 46 |           android:text="@string/logApp"
 47 |           android:textColor="@color/text_color"
 48 |           android:textSize="32dp"
 49 |           tools:ignore="RelativeOverlap" />
 50 |     </RelativeLayout>
 51 | 
 52 |     <ScrollView
 53 |         android:id="@+id/logScrollView"
 54 |         android:layout_width="match_parent"
 55 |         android:layout_height="0dp"
 56 |         android:layout_marginHorizontal="16dp"
 57 |         android:layout_marginTop="16dp"
 58 |         app:layout_constraintTop_toBottomOf="@id/top_bar"
 59 |         app:layout_constraintBottom_toTopOf="@id/copytoclip"
 60 |         app:layout_constraintEnd_toEndOf="parent"
 61 |         app:layout_constraintStart_toStartOf="parent"
 62 |         android:focusable="true"
 63 |         android:nextFocusUp="@id/back"
 64 |         android:nextFocusDown="@id/copytoclip">
 65 | 
 66 |       <TextView
 67 |           android:id="@+id/logs"
 68 |           android:layout_width="match_parent"
 69 |           android:layout_height="wrap_content"
 70 |           android:textColor="@color/subtitle_color"
 71 |           android:text="Start Logging Here.."
 72 |           android:textSize="11dp" />
 73 |     </ScrollView>
 74 | 
 75 |     <Button
 76 |         android:id="@+id/copytoclip"
 77 |         android:layout_width="match_parent"
 78 |         android:layout_height="wrap_content"
 79 |         android:background="@color/primary"
 80 |         android:fontFamily="@font/shabnam"
 81 |         android:text="@string/copytoclip"
 82 |         android:textColor="@color/white"
 83 |         android:textSize="18dp"
 84 |         app:layout_constraintBottom_toBottomOf="parent"
 85 |         app:layout_constraintEnd_toEndOf="parent"
 86 |         app:layout_constraintStart_toStartOf="parent"
 87 |         android:focusable="true"
 88 |         android:nextFocusUp="@id/logScrollView" />
 89 | 
 90 |     <FrameLayout
 91 |         android:id="@+id/progress_container"
 92 |         android:layout_width="wrap_content"
 93 |         android:layout_height="wrap_content"
 94 |         app:layout_constraintBottom_toBottomOf="parent"
 95 |         app:layout_constraintEnd_toEndOf="parent"
 96 |         app:layout_constraintStart_toStartOf="parent"
 97 |         app:layout_constraintTop_toTopOf="parent"
 98 |         app:layout_constraintVertical_bias="0.5"
 99 |         app:layout_constraintHorizontal_bias="0.5"
100 |         android:visibility="gone">
101 | 
102 |       <ProgressBar
103 |           android:id="@+id/progressBar"
104 |           android:layout_width="100dp"
105 |           android:layout_height="100dp"
106 |           android:indeterminate="true"
107 |           android:layout_gravity="center"
108 |           style="@style/CustomProgressBar"/>
109 | 
110 |       <TextView
111 |           android:id="@+id/loadingText"
112 |           android:layout_width="wrap_content"
113 |           android:layout_height="wrap_content"
114 |           android:layout_gravity="center"
115 |           android:text="Getting ISP..."
116 |           android:textColor="@android:color/white"
117 |           android:textSize="16dp"
118 |           android:padding="8dp"/>
119 |     </FrameLayout>
120 | 
121 |   </androidx.constraintlayout.widget.ConstraintLayout>
122 | </layout>


--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_splash_screen.xml:
--------------------------------------------------------------------------------
  1 | <?xml version="1.0" encoding="utf-8"?>
  2 | <layout xmlns:android="http://schemas.android.com/apk/res/android"
  3 |     xmlns:app="http://schemas.android.com/apk/res-auto"
  4 |     xmlns:tools="http://schemas.android.com/tools">
  5 | 
  6 |     <data>
  7 | 
  8 |         <variable
  9 |             name="handler"
 10 |             type="org.bepass.oblivion.ui.SplashScreenActivity.ClickHandler" />
 11 |     </data>
 12 | 
 13 |     <androidx.constraintlayout.widget.ConstraintLayout
 14 |         android:id="@+id/splashScreen"
 15 |         android:layout_width="match_parent"
 16 |         android:layout_height="match_parent"
 17 |         android:background="@color/background"
 18 |         android:fitsSystemWindows="true"
 19 |         android:onClick="@{handler::OnRootPressed}">
 20 | 
 21 |         <androidx.constraintlayout.widget.ConstraintLayout
 22 |             android:id="@+id/constraintLayout3"
 23 |             android:layout_width="0dp"
 24 |             android:layout_height="0dp"
 25 |             android:padding="16sp"
 26 |             app:layout_constraintBottom_toTopOf="@+id/textView5"
 27 |             app:layout_constraintEnd_toEndOf="parent"
 28 |             app:layout_constraintStart_toStartOf="parent"
 29 |             app:layout_constraintTop_toTopOf="parent">
 30 | 
 31 |             <com.google.android.material.imageview.ShapeableImageView
 32 |                 android:id="@+id/shapeableImageView"
 33 |                 android:layout_width="0dp"
 34 |                 android:layout_height="wrap_content"
 35 |                 android:cropToPadding="false"
 36 |                 style="@style/basedOnTheme"
 37 |                 android:src="@drawable/segaro"
 38 |                 app:layout_constraintEnd_toEndOf="parent"
 39 |                 app:layout_constraintStart_toStartOf="parent"
 40 |                 app:layout_constraintTop_toTopOf="parent" />
 41 | 
 42 |             <TextView
 43 |                 android:id="@+id/textView"
 44 |                 android:layout_width="wrap_content"
 45 |                 android:layout_height="wrap_content"
 46 |                 android:text="@string/app_name"
 47 |                 android:textAllCaps="true"
 48 |                 android:textColor="@color/primary"
 49 |                 android:textSize="48dp"
 50 |                 android:textStyle="bold"
 51 |                 app:layout_constraintEnd_toEndOf="parent"
 52 |                 app:layout_constraintStart_toStartOf="parent"
 53 |                 app:layout_constraintTop_toBottomOf="@+id/shapeableImageView" />
 54 | 
 55 |             <TextView
 56 |                 android:id="@+id/textView2"
 57 |                 android:layout_width="wrap_content"
 58 |                 android:layout_height="wrap_content"
 59 |                 android:fontFamily="@font/shabnammedium"
 60 |                 android:gravity="center"
 61 |                 android:text="@string/means"
 62 |                 android:textAlignment="textEnd"
 63 |                 android:textColor="@color/text_color"
 64 |                 android:textSize="20dp"
 65 |                 app:layout_constraintBottom_toBottomOf="parent"
 66 |                 app:layout_constraintEnd_toEndOf="parent"
 67 |                 app:layout_constraintHorizontal_bias="0.502"
 68 |                 app:layout_constraintStart_toStartOf="parent"
 69 |                 app:layout_constraintTop_toBottomOf="@+id/textView"
 70 |                 app:layout_constraintVertical_bias="0.05"
 71 |                 tools:ignore="RtlCompat" />
 72 | 
 73 |             <LinearLayout
 74 |                 android:layout_width="0dp"
 75 |                 android:layout_height="wrap_content"
 76 |                 android:padding="15dp"
 77 |                 app:layout_constraintEnd_toEndOf="parent"
 78 |                 app:layout_constraintStart_toStartOf="parent"
 79 |                 app:layout_constraintTop_toBottomOf="@+id/textView2">
 80 | 
 81 |                 <com.google.android.material.imageview.ShapeableImageView
 82 |                     android:layout_width="wrap_content"
 83 |                     android:layout_height="wrap_content"
 84 |                     android:src="@drawable/yousef" />
 85 | 
 86 |                 <TextView
 87 |                     android:layout_width="wrap_content"
 88 |                     android:layout_height="wrap_content"
 89 |                     android:fontFamily="@font/shabnammedium"
 90 |                     android:gravity="center"
 91 |                     android:paddingHorizontal="15dp"
 92 |                     android:paddingTop="5dp"
 93 |                     android:text="@string/splashText"
 94 |                     android:textAlignment="textStart"
 95 |                     android:textColor="@color/text_color"
 96 |                     android:textSize="15dp"
 97 |                     tools:ignore="RtlCompat" />
 98 |             </LinearLayout>
 99 |         </androidx.constraintlayout.widget.ConstraintLayout>
100 | 
101 | 
102 |         <TextView
103 |             android:id="@+id/textView5"
104 |             android:layout_width="fill_parent"
105 |             android:layout_height="80dp"
106 |             android:fontFamily="@font/shabnammedium"
107 |             android:gravity="center"
108 |             android:text="@string/slogan"
109 |             android:textAlignment="center"
110 |             android:textColor="@color/subtitle_color"
111 |             android:textSize="20dp"
112 |             android:textStyle="bold"
113 |             app:layout_constraintBottom_toBottomOf="parent"
114 |             app:layout_constraintEnd_toEndOf="parent"
115 |             app:layout_constraintStart_toStartOf="parent" />
116 | 
117 |     </androidx.constraintlayout.widget.ConstraintLayout>
118 | </layout>
119 | 


--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_split_tunnel.xml:
--------------------------------------------------------------------------------
 1 | <?xml version="1.0" encoding="utf-8"?>
 2 | <layout xmlns:android="http://schemas.android.com/apk/res/android"
 3 |     xmlns:app="http://schemas.android.com/apk/res-auto"
 4 |     xmlns:tools="http://schemas.android.com/tools">
 5 | 
 6 |     <data>
 7 | 
 8 |     </data>
 9 | 
10 |     <androidx.constraintlayout.widget.ConstraintLayout
11 |         android:layout_width="match_parent"
12 |         android:layout_height="match_parent"
13 |         android:background="@color/background"
14 |         android:orientation="vertical"
15 |         tools:context=".ui.SplitTunnelActivity"
16 |         android:fitsSystemWindows="true">
17 | 
18 |         <RelativeLayout
19 |             android:id="@+id/top_bar"
20 |             android:layout_width="match_parent"
21 |             android:layout_height="48dp"
22 |             android:layout_marginTop="8dp"
23 |             app:layout_constraintEnd_toEndOf="parent"
24 |             app:layout_constraintStart_toStartOf="parent"
25 |             app:layout_constraintTop_toTopOf="parent">
26 | 
27 |             <org.bepass.oblivion.component.Icon
28 |                 android:id="@+id/back"
29 |                 android:layout_width="35dp"
30 |                 android:layout_height="35dp"
31 |                 android:background="?android:selectableItemBackground"
32 |                 android:layout_alignParentStart="true"
33 |                 android:layout_centerVertical="true"
34 |                 android:layout_marginStart="16dp"
35 |                 android:src="@drawable/ic_back"
36 |                 app:icon_color="@color/icon_color"
37 |                 app:tint="@color/icon_color"
38 |                 android:focusable="true"
39 |                 android:nextFocusDown="@id/appsRecycler" />
40 | 
41 |             <TextView
42 |                 android:layout_width="wrap_content"
43 |                 android:layout_height="wrap_content"
44 |                 android:layout_alignParentEnd="true"
45 |                 android:layout_centerVertical="true"
46 |                 android:layout_marginEnd="16dp"
47 |                 android:fontFamily="@font/shabnamlight"
48 |                 android:text="@string/blackList"
49 |                 android:textColor="@color/text_color"
50 |                 android:textSize="24dp"
51 |                 tools:ignore="RelativeOverlap"
52 |                 android:focusable="true"
53 |                 android:nextFocusDown="@id/appsRecycler" />
54 | 
55 |         </RelativeLayout>
56 | 
57 |         <androidx.recyclerview.widget.RecyclerView
58 |             android:id="@+id/appsRecycler"
59 |             android:layout_width="0dp"
60 |             android:layout_height="0dp"
61 |             android:visibility="gone"
62 |             app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager"
63 |             app:layout_constraintBottom_toBottomOf="parent"
64 |             app:layout_constraintEnd_toEndOf="parent"
65 |             app:layout_constraintStart_toStartOf="parent"
66 |             app:layout_constraintTop_toBottomOf="@+id/top_bar"
67 |             tools:itemCount="20"
68 |             tools:listitem="@layout/installed_app_item"
69 |             tools:visibility="visible"
70 |             android:focusable="true"
71 |             android:nextFocusUp="@id/top_bar"
72 |             android:nextFocusDown="@id/progress" />
73 | 
74 |         <com.google.android.material.progressindicator.CircularProgressIndicator
75 |             android:id="@+id/progress"
76 |             android:layout_width="wrap_content"
77 |             android:layout_height="wrap_content"
78 |             android:indeterminate="true"
79 |             android:indeterminateOnly="true"
80 |             app:indicatorColor="@color/primary"
81 |             app:layout_constraintBottom_toBottomOf="parent"
82 |             app:layout_constraintEnd_toEndOf="parent"
83 |             app:layout_constraintStart_toStartOf="parent"
84 |             app:layout_constraintTop_toTopOf="parent"
85 |             android:focusable="true"
86 |             android:nextFocusUp="@id/appsRecycler" />
87 | 
88 |     </androidx.constraintlayout.widget.ConstraintLayout>
89 | </layout>
90 | 


--------------------------------------------------------------------------------
/app/src/main/res/layout/bottom_sheet_endpoints.xml:
--------------------------------------------------------------------------------
  1 | <?xml version="1.0" encoding="utf-8"?>
  2 | <ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
  3 |     xmlns:app="http://schemas.android.com/apk/res-auto"
  4 |     android:layout_width="match_parent"
  5 |     android:layout_height="wrap_content"
  6 |     android:fillViewport="true"
  7 |     android:background="@drawable/rounded_bottom_sheet">
  8 | 
  9 |     <LinearLayout
 10 |         android:layout_width="match_parent"
 11 |         android:layout_height="wrap_content"
 12 |         android:orientation="vertical"
 13 |         android:padding="20dp"
 14 |         android:background="@drawable/endpoint_sheet">
 15 | 
 16 |         <View
 17 |             android:id="@+id/dividingCloser"
 18 |             android:layout_width="64dp"
 19 |             android:layout_height="5dp"
 20 |             android:layout_gravity="center_horizontal"
 21 |             android:layout_marginTop="8dp"
 22 |             android:background="@drawable/bottom_sheet_closer" />
 23 | 
 24 |         <TextView
 25 |             android:id="@+id/title"
 26 |             android:layout_width="wrap_content"
 27 |             android:layout_height="wrap_content"
 28 |             android:layout_gravity="center"
 29 |             android:layout_marginTop="16dp"
 30 |             android:fontFamily="@font/shabnam"
 31 |             android:text="@string/editSheetEndpoint"
 32 |             android:textColor="@color/text_color"
 33 |             android:textSize="20sp"
 34 |             android:textStyle="bold" />
 35 | 
 36 |         <!-- Title Field -->
 37 |         <TextView
 38 |             android:layout_width="match_parent"
 39 |             android:layout_height="wrap_content"
 40 |             android:layout_marginTop="24dp"
 41 |             android:layout_marginBottom="5dp"
 42 |             android:text="@string/title"
 43 |             android:textColor="@color/text_color"
 44 |             android:fontFamily="@font/shabnam"
 45 |             android:textSize="14sp" />
 46 | 
 47 |         <EditText
 48 |             android:id="@+id/titleEditText"
 49 |             android:layout_width="match_parent"
 50 |             android:layout_height="wrap_content"
 51 |             android:background="@drawable/edittext_back"
 52 |             android:fontFamily="@font/shabnam"
 53 |             android:padding="10dp"
 54 |             android:textSize="14sp"
 55 |             android:hint="@string/title"
 56 |             android:textColorHint="@color/text_color"
 57 |             android:textColor="@color/text_color"
 58 |             android:singleLine="true" />
 59 | 
 60 |         <!-- Content Field -->
 61 |         <TextView
 62 |             android:layout_width="match_parent"
 63 |             android:layout_height="wrap_content"
 64 |             android:layout_marginTop="16dp"
 65 |             android:layout_marginBottom="5dp"
 66 |             android:text="@string/content"
 67 |             android:textColor="@color/text_color"
 68 |             android:fontFamily="@font/shabnam"
 69 |             android:textSize="14sp" />
 70 | 
 71 |         <EditText
 72 |             android:id="@+id/contentEditText"
 73 |             android:layout_width="match_parent"
 74 |             android:layout_height="wrap_content"
 75 |             android:background="@drawable/edittext_back"
 76 |             android:fontFamily="@font/shabnam"
 77 |             android:padding="10dp"
 78 |             android:textSize="14sp"
 79 |             android:hint="@string/content"
 80 |             android:textColorHint="@color/text_color"
 81 |             android:textColor="@color/text_color"
 82 |             android:textAlignment="viewStart"
 83 |             android:inputType="text"
 84 |             android:singleLine="true" />
 85 | 
 86 |         <!-- Save Button -->
 87 |         <Button
 88 |             android:id="@+id/saveButton"
 89 |             android:layout_width="match_parent"
 90 |             android:layout_height="wrap_content"
 91 |             android:layout_marginTop="24dp"
 92 |             android:background="@drawable/button"
 93 |             android:fontFamily="@font/shabnambold"
 94 |             android:text="@string/save"
 95 |             android:textColor="@color/white"
 96 |             android:textSize="16sp" />
 97 | 
 98 |         <!-- Reset Button -->
 99 |         <Button
100 |             android:id="@+id/resetDefaultButton"
101 |             android:layout_width="match_parent"
102 |             android:layout_height="wrap_content"
103 |             android:layout_marginTop="12dp"
104 |             android:background="@drawable/button_op"
105 |             android:fontFamily="@font/shabnambold"
106 |             android:text="@string/reset_to_default_endpoint"
107 |             android:textColor="@color/white"
108 |             android:textSize="16sp" />
109 | 
110 |         <!-- Saved endpoints title -->
111 |         <TextView
112 |             android:layout_width="wrap_content"
113 |             android:layout_height="wrap_content"
114 |             android:layout_marginTop="24dp"
115 |             android:fontFamily="@font/shabnam"
116 |             android:text="@string/saved_endpoints"
117 |             android:textColor="@color/text_color"
118 |             android:textSize="16sp"
119 |             android:textStyle="bold" />
120 | 
121 |         <androidx.recyclerview.widget.RecyclerView
122 |             android:id="@+id/recyclerView"
123 |             android:layout_width="match_parent"
124 |             android:layout_height="wrap_content"
125 |             android:layout_marginTop="12dp"
126 |             android:background="@color/background" />
127 |     </LinearLayout>
128 | </ScrollView>


--------------------------------------------------------------------------------
/app/src/main/res/layout/country_item_layout.xml:
--------------------------------------------------------------------------------
1 | <!-- spinner_item_layout.xml -->
2 | <TextView xmlns:android="http://schemas.android.com/apk/res/android"
3 |   android:layout_width="match_parent"
4 |   android:layout_height="wrap_content"
5 |   android:paddingLeft="5dp"
6 |   android:textSize="18dp"
7 |     android:textColor="@color/text_color"
8 |   android:fontFamily="@font/shabnammedium" />
9 | 


--------------------------------------------------------------------------------
/app/src/main/res/layout/dialog_battery_optimization.xml:
--------------------------------------------------------------------------------
 1 | <?xml version="1.0" encoding="utf-8"?>
 2 | <layout xmlns:android="http://schemas.android.com/apk/res/android"
 3 |     xmlns:tools="http://schemas.android.com/tools">
 4 | 
 5 |     <data>
 6 |         <!-- Define any variables if needed -->
 7 |     </data>
 8 | 
 9 |     <LinearLayout
10 |         android:layout_width="match_parent"
11 |         android:layout_height="wrap_content"
12 |         android:orientation="vertical"
13 |         android:padding="16dp"
14 |         android:background="@color/background">
15 | 
16 |         <TextView
17 |             android:id="@+id/dialog_title"
18 |             android:layout_width="wrap_content"
19 |             android:layout_height="wrap_content"
20 |             android:layout_gravity="center"
21 |             android:layout_marginTop="16dp"
22 |             android:fontFamily="@font/shabnam"
23 |             android:text="@string/batteryOpL"
24 |             android:textColor="@color/text_color"
25 |             android:textSize="20dp"
26 |             android:textStyle="bold"
27 |             android:focusable="true" />
28 | 
29 |         <TextView
30 |             android:id="@+id/dialog_message"
31 |             android:layout_width="wrap_content"
32 |             android:layout_height="wrap_content"
33 |             android:layout_gravity="center"
34 |             android:layout_marginTop="8dp"
35 |             android:fontFamily="@font/shabnam"
36 |             android:text="@string/dialBtText"
37 |             android:textColor="@color/subtitle_color"
38 |             android:textSize="16dp"
39 |             android:focusable="true" />
40 | 
41 |         <LinearLayout
42 |             style="?android:attr/buttonBarStyle"
43 |             android:layout_width="match_parent"
44 |             android:layout_height="wrap_content"
45 |             android:layout_marginTop="24dp"
46 |             android:weightSum="2"
47 |             android:gravity="end"
48 |             android:orientation="horizontal">
49 | 
50 |             <Button
51 |                 android:id="@+id/dialog_button_negative"
52 |                 style="?android:attr/buttonBarButtonStyle"
53 |                 android:layout_width="0dp"
54 |                 android:layout_weight="1"
55 |                 android:layout_marginEnd="8dp"
56 |                 android:layout_height="wrap_content"
57 |                 android:background="?attr/selectableItemBackground"
58 |                 android:fontFamily="@font/shabnambold"
59 |                 android:text="@string/cancel"
60 |                 android:textColor="@color/text_color"
61 |                 android:focusable="true" />
62 | 
63 |             <Button
64 |                 android:id="@+id/dialog_button_positive"
65 |                 style="?android:attr/buttonBarButtonStyle"
66 |                 android:layout_width="0dp"
67 |                 android:layout_marginStart="8dp"
68 |                 android:layout_weight="1"
69 |                 android:layout_height="wrap_content"
70 |                 android:background="#FFA200"
71 |                 android:fontFamily="@font/shabnambold"
72 |                 android:text="@string/goToSettings"
73 |                 android:textColor="@color/white"
74 |                 android:focusable="true" />
75 |         </LinearLayout>
76 | 
77 |     </LinearLayout>
78 | </layout>
79 | 


--------------------------------------------------------------------------------
/app/src/main/res/layout/edit_sheet.xml:
--------------------------------------------------------------------------------
 1 | <?xml version="1.0" encoding="utf-8"?>
 2 | <ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
 3 |     android:layout_width="match_parent"
 4 |     android:layout_height="wrap_content"
 5 |     android:fillViewport="true"
 6 |     android:background="@drawable/rounded_bottom_sheet">
 7 | 
 8 |   <LinearLayout
 9 |       android:background="@color/background"
10 |       android:layout_width="match_parent"
11 |       android:layout_height="wrap_content"
12 |       android:gravity="center"
13 |       android:orientation="vertical">
14 | 
15 |     <View
16 |         android:id="@+id/dividingCloser"
17 |         android:layout_width="64sp"
18 |         android:layout_height="5dp"
19 |         android:layout_marginTop="8sp"
20 |         android:background="@drawable/bottom_sheet_closer" />
21 | 
22 |     <TextView
23 |         android:id="@+id/title"
24 |         android:layout_width="wrap_content"
25 |         android:layout_height="wrap_content"
26 |         android:layout_marginTop="16sp"
27 |         android:fontFamily="@font/shabnam"
28 |         android:text="@string/editSheetEndpoint"
29 |         android:textColor="@color/text_color"
30 |         android:textSize="18dp" />
31 | 
32 |     <EditText
33 |         android:id="@+id/edittext"
34 |         android:layout_width="match_parent"
35 |         android:layout_height="48sp"
36 |         android:layout_marginHorizontal="16sp"
37 |         android:layout_marginTop="12sp"
38 |         android:inputType="text"
39 |         android:background="@drawable/edittext_back"
40 |         android:fontFamily="@font/shabnam"
41 |         android:lineSpacingExtra="4sp"
42 |         android:padding="12sp"
43 |         android:singleLine="true"
44 |         android:textAlignment="center"
45 |         android:textColor="@color/text_color"
46 |         android:textSize="15dp"
47 |         android:nextFocusDown="@+id/cancelButton" />
48 | 
49 |     <LinearLayout
50 |         style="?android:attr/buttonBarStyle"
51 |         android:layout_width="match_parent"
52 |         android:layout_height="wrap_content"
53 |         android:layout_marginHorizontal="16sp"
54 |         android:layout_marginVertical="12sp"
55 |         android:orientation="horizontal">
56 | 
57 |       <Button
58 |           android:id="@+id/cancelButton"
59 |           style="?android:attr/buttonBarButtonStyle"
60 |           android:layout_width="0sp"
61 |           android:layout_height="wrap_content"
62 |           android:layout_marginEnd="8sp"
63 |           android:layout_weight="1"
64 |           android:background="@drawable/bottom_sheet_cancel"
65 |           android:fontFamily="@font/shabnambold"
66 |           android:text="@string/cancel"
67 |           android:textColor="@color/text_color"
68 |           android:textSize="17dp"
69 |           android:focusable="true"
70 |           android:nextFocusRight="@+id/applyButton"
71 |           android:nextFocusUp="@+id/edittext" />
72 | 
73 |       <Button
74 |           android:id="@+id/applyButton"
75 |           style="?android:attr/buttonBarButtonStyle"
76 |           android:layout_width="0sp"
77 |           android:layout_height="wrap_content"
78 |           android:layout_marginEnd="8sp"
79 |           android:layout_weight="1"
80 |           android:background="@drawable/bottom_sheet_closer"
81 |           android:fontFamily="@font/shabnambold"
82 |           android:text="@string/update"
83 |           android:textColor="@color/white"
84 |           android:textSize="17dp"
85 |           android:focusable="true"
86 |           android:nextFocusLeft="@+id/cancelButton"
87 |           android:nextFocusUp="@+id/edittext" />
88 | 
89 |     </LinearLayout>
90 |   </LinearLayout>
91 | </ScrollView>
92 | 


--------------------------------------------------------------------------------
/app/src/main/res/layout/installed_app_item.xml:
--------------------------------------------------------------------------------
 1 | <?xml version="1.0" encoding="utf-8"?>
 2 | <androidx.constraintlayout.widget.ConstraintLayout
 3 |     xmlns:android="http://schemas.android.com/apk/res/android"
 4 |     xmlns:tools="http://schemas.android.com/tools"
 5 |     xmlns:app="http://schemas.android.com/apk/res-auto"
 6 |     android:layout_width="match_parent"
 7 |     android:layout_height="wrap_content"
 8 |     android:background="?android:selectableItemBackground"
 9 |     android:orientation="horizontal"
10 |     android:padding="16dp"
11 |     android:fitsSystemWindows="true">
12 | 
13 |     <com.google.android.material.imageview.ShapeableImageView
14 |         android:id="@+id/icon"
15 |         android:layout_width="48dp"
16 |         android:layout_height="48dp"
17 |         app:layout_constraintStart_toStartOf="parent"
18 |         app:layout_constraintTop_toTopOf="parent"
19 |         app:shapeAppearanceOverlay="@style/circleImageView"
20 |         android:focusable="true"
21 |         android:nextFocusRight="@id/appNameTextView"
22 |         android:nextFocusDown="@id/checkBox"
23 |         />
24 | 
25 |     <TextView
26 |         android:id="@+id/appNameTextView"
27 |         android:layout_width="0dp"
28 |         android:layout_height="wrap_content"
29 |         android:layout_gravity="center"
30 |         android:layout_weight="1"
31 |         android:padding="8dp"
32 |         android:fontFamily="@font/shabnam"
33 |         android:textStyle="bold"
34 |         android:textColor="@color/text_color"
35 |         android:textSize="16dp"
36 |         app:layout_constraintBottom_toBottomOf="@+id/icon"
37 |         app:layout_constraintEnd_toStartOf="@+id/checkBox"
38 |         app:layout_constraintStart_toEndOf="@+id/icon"
39 |         app:layout_constraintTop_toTopOf="@+id/icon"
40 |         tools:text="Installed app name"
41 |         android:focusable="true"
42 |         android:nextFocusLeft="@id/icon"
43 |         android:nextFocusRight="@id/checkBox"
44 |         />
45 | 
46 |     <CheckBox
47 |         android:id="@+id/checkBox"
48 |         android:layout_width="wrap_content"
49 |         android:layout_height="wrap_content"
50 |         android:layout_gravity="center"
51 |         android:buttonTint="@color/checkbox_tint"
52 |         android:clickable="false"
53 |         android:focusable="true"
54 |         app:layout_constraintBottom_toBottomOf="parent"
55 |         app:layout_constraintEnd_toEndOf="parent"
56 |         app:layout_constraintTop_toTopOf="parent"
57 |         android:nextFocusLeft="@id/appNameTextView"
58 |         android:nextFocusUp="@id/icon"
59 |         />
60 | 
61 | </androidx.constraintlayout.widget.ConstraintLayout>
62 | 


--------------------------------------------------------------------------------
/app/src/main/res/layout/item_endpoint.xml:
--------------------------------------------------------------------------------
 1 | <?xml version="1.0" encoding="utf-8"?>
 2 | <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
 3 |     android:layout_width="match_parent"
 4 |     android:layout_height="wrap_content"
 5 |     android:orientation="horizontal"
 6 |     android:padding="8dp">
 7 | 
 8 |     <TextView
 9 |         android:id="@+id/titleTextView"
10 |         android:layout_width="0dp"
11 |         android:layout_height="wrap_content"
12 |         android:layout_weight="1"
13 |         android:textSize="16sp"
14 |         android:textColor="@color/text_color" />
15 | 
16 |     <TextView
17 |         android:id="@+id/contentTextView"
18 |         android:layout_width="0dp"
19 |         android:layout_height="wrap_content"
20 |         android:layout_weight="2"
21 |         android:textSize="16sp"
22 |         android:textColor="@color/text_color" />
23 | 
24 |     <ImageView
25 |         android:id="@+id/delIcon"
26 |         android:layout_width="40dp"
27 |         android:layout_height="40dp"
28 |         android:src="@android:drawable/ic_menu_close_clear_cancel" />
29 | </LinearLayout>


--------------------------------------------------------------------------------
/app/src/main/res/layout/split_tunnel_options.xml:
--------------------------------------------------------------------------------
  1 | <?xml version="1.0" encoding="utf-8"?>
  2 | <androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
  3 |     xmlns:app="http://schemas.android.com/apk/res-auto"
  4 |     xmlns:tools="http://schemas.android.com/tools"
  5 |     android:layout_width="match_parent"
  6 |     android:layout_height="wrap_content"
  7 |     android:background="@color/background"
  8 |     android:fitsSystemWindows="true">
  9 | 
 10 |     <RadioGroup
 11 |         android:id="@+id/radioGroup"
 12 |         android:layout_width="match_parent"
 13 |         android:layout_height="wrap_content"
 14 |         android:checkedButton="@+id/disabled"
 15 |         app:layout_constraintEnd_toEndOf="parent"
 16 |         app:layout_constraintStart_toStartOf="parent"
 17 |         app:layout_constraintTop_toTopOf="parent">
 18 | 
 19 |         <RadioButton
 20 |             android:id="@+id/disabled"
 21 |             android:layout_width="match_parent"
 22 |             android:layout_height="wrap_content"
 23 |             android:layout_gravity="start"
 24 |             android:background="?android:selectableItemBackground"
 25 |             android:button="@null"
 26 |             android:drawableRight="?android:attr/listChoiceIndicatorSingle"
 27 |             android:fontFamily="@font/shabnam"
 28 |             android:layoutDirection="rtl"
 29 |             android:paddingLeft="20dp"
 30 |             android:paddingTop="10dp"
 31 |             android:textColor="@color/text_color"
 32 |             android:paddingRight="20dp"
 33 |             android:paddingBottom="10dp"
 34 |             android:text="@string/disabledR"
 35 |             android:textAlignment="textStart"
 36 |             android:textSize="14dp"
 37 |             android:focusable="true"
 38 |             android:nextFocusDown="@id/blacklist" />
 39 | 
 40 |         <TextView
 41 |             android:layout_width="match_parent"
 42 |             android:layout_height="wrap_content"
 43 |             android:layout_gravity="start"
 44 |             android:fontFamily="@font/shabnam"
 45 |             android:layoutDirection="rtl"
 46 |             android:paddingLeft="20dp"
 47 |             android:paddingRight="20dp"
 48 |             android:paddingBottom="10dp"
 49 |             android:text="@string/disabledRText"
 50 |             android:textColor="@color/subtitle_color"
 51 |             android:textAlignment="textStart"
 52 |             android:textSize="14dp" />
 53 | 
 54 |         <RadioButton
 55 |             android:id="@+id/blacklist"
 56 |             android:layout_width="match_parent"
 57 |             android:layout_height="wrap_content"
 58 |             android:layout_gravity="start"
 59 |             android:background="?android:selectableItemBackground"
 60 |             android:button="@null"
 61 |             android:textColor="@color/text_color"
 62 |             android:drawableRight="?android:attr/listChoiceIndicatorSingle"
 63 |             android:fontFamily="@font/shabnam"
 64 |             android:layoutDirection="rtl"
 65 |             android:paddingLeft="20dp"
 66 |             android:paddingTop="10dp"
 67 |             android:paddingRight="20dp"
 68 |             android:paddingBottom="10dp"
 69 |             android:text="@string/enabledR"
 70 |             android:textAlignment="textStart"
 71 |             android:textSize="14dp"
 72 |             android:focusable="true"
 73 |             android:nextFocusUp="@id/disabled"
 74 |             android:nextFocusDown="@id/showSystemApps" />
 75 | 
 76 |         <TextView
 77 |             android:layout_width="match_parent"
 78 |             android:layout_height="wrap_content"
 79 |             android:layout_gravity="start"
 80 |             android:fontFamily="@font/shabnam"
 81 |             android:layoutDirection="rtl"
 82 |             android:paddingLeft="20dp"
 83 |             android:paddingRight="20dp"
 84 |             android:textColor="@color/subtitle_color"
 85 |             android:paddingBottom="10dp"
 86 |             android:text="@string/enabledRText"
 87 |             android:textAlignment="textStart"
 88 |             android:textSize="14dp" />
 89 |     </RadioGroup>
 90 | 
 91 |     <com.google.android.material.switchmaterial.SwitchMaterial
 92 |         android:id="@+id/showSystemApps"
 93 |         android:layout_width="wrap_content"
 94 |         android:layout_height="wrap_content"
 95 |         android:layout_marginTop="8dp"
 96 |         android:checked="false"
 97 |         android:textColor="@color/text_color"
 98 |         android:fontFamily="@font/shabnam"
 99 |         android:padding="4dp"
100 |         android:text="@string/showSystemAppsText"
101 |         android:focusable="true"
102 |         app:layout_constraintEnd_toEndOf="parent"
103 |         app:layout_constraintTop_toBottomOf="@+id/radioGroup"
104 |         app:switchPadding="4dp"
105 |         android:nextFocusUp="@id/blacklist" />
106 | </androidx.constraintlayout.widget.ConstraintLayout>
107 | 


--------------------------------------------------------------------------------
/app/src/main/res/layout/toast.xml:
--------------------------------------------------------------------------------
 1 | <?xml version="1.0" encoding="utf-8"?>
 2 | <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
 3 |     xmlns:app="http://schemas.android.com/apk/res-auto"
 4 |     android:id="@+id/toast_layout"
 5 |     android:layout_width="wrap_content"
 6 |     android:layout_height="wrap_content"
 7 |     android:background="@drawable/toast_background"
 8 |     android:orientation="horizontal"
 9 |     android:fitsSystemWindows="true">
10 | 
11 |     <ImageView
12 |         android:layout_width="wrap_content"
13 |         android:layout_height="wrap_content"
14 |         android:src="@drawable/check"
15 |         android:textAlignment="center"
16 |         android:layout_gravity="center|center_vertical|center_horizontal"
17 |         android:padding="6dp"
18 |         app:tint="@color/white" />
19 | 
20 |     <TextView
21 |         android:layout_width="wrap_content"
22 |         android:layout_height="wrap_content"
23 |         android:layout_margin="8dp"
24 |         android:text="@string/copied_to_clipboard"
25 |         android:textColor="@color/white"
26 |         android:textSize="16dp" />
27 | </LinearLayout>
28 | 


--------------------------------------------------------------------------------
/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml:
--------------------------------------------------------------------------------
1 | <?xml version="1.0" encoding="utf-8"?>
2 | <adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
3 |   <background android:drawable="@color/ic_launcher_background" />
4 |   <foreground android:drawable="@mipmap/ic_launcher_foreground" />
5 | </adaptive-icon>
6 | 


--------------------------------------------------------------------------------
/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml:
--------------------------------------------------------------------------------
1 | <?xml version="1.0" encoding="utf-8"?>
2 | <adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
3 |   <background android:drawable="@color/ic_launcher_background" />
4 |   <foreground android:drawable="@mipmap/ic_launcher_foreground" />
5 | </adaptive-icon>
6 | 


--------------------------------------------------------------------------------
/app/src/main/res/mipmap-hdpi/ic_launcher.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bepass-org/oblivion/2ed61afd06003949a59f0bfec7281cfb80814e1e/app/src/main/res/mipmap-hdpi/ic_launcher.webp


--------------------------------------------------------------------------------
/app/src/main/res/mipmap-hdpi/ic_launcher_foreground.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bepass-org/oblivion/2ed61afd06003949a59f0bfec7281cfb80814e1e/app/src/main/res/mipmap-hdpi/ic_launcher_foreground.webp


--------------------------------------------------------------------------------
/app/src/main/res/mipmap-hdpi/ic_launcher_round.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bepass-org/oblivion/2ed61afd06003949a59f0bfec7281cfb80814e1e/app/src/main/res/mipmap-hdpi/ic_launcher_round.webp


--------------------------------------------------------------------------------
/app/src/main/res/mipmap-hdpi/ic_notification.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bepass-org/oblivion/2ed61afd06003949a59f0bfec7281cfb80814e1e/app/src/main/res/mipmap-hdpi/ic_notification.png


--------------------------------------------------------------------------------
/app/src/main/res/mipmap-mdpi/ic_launcher.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bepass-org/oblivion/2ed61afd06003949a59f0bfec7281cfb80814e1e/app/src/main/res/mipmap-mdpi/ic_launcher.webp


--------------------------------------------------------------------------------
/app/src/main/res/mipmap-mdpi/ic_launcher_foreground.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bepass-org/oblivion/2ed61afd06003949a59f0bfec7281cfb80814e1e/app/src/main/res/mipmap-mdpi/ic_launcher_foreground.webp


--------------------------------------------------------------------------------
/app/src/main/res/mipmap-mdpi/ic_launcher_round.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bepass-org/oblivion/2ed61afd06003949a59f0bfec7281cfb80814e1e/app/src/main/res/mipmap-mdpi/ic_launcher_round.webp


--------------------------------------------------------------------------------
/app/src/main/res/mipmap-mdpi/ic_notification.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bepass-org/oblivion/2ed61afd06003949a59f0bfec7281cfb80814e1e/app/src/main/res/mipmap-mdpi/ic_notification.png


--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xhdpi/ic_launcher.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bepass-org/oblivion/2ed61afd06003949a59f0bfec7281cfb80814e1e/app/src/main/res/mipmap-xhdpi/ic_launcher.webp


--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xhdpi/ic_launcher_foreground.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bepass-org/oblivion/2ed61afd06003949a59f0bfec7281cfb80814e1e/app/src/main/res/mipmap-xhdpi/ic_launcher_foreground.webp


--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xhdpi/ic_launcher_round.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bepass-org/oblivion/2ed61afd06003949a59f0bfec7281cfb80814e1e/app/src/main/res/mipmap-xhdpi/ic_launcher_round.webp


--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xhdpi/ic_notification.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bepass-org/oblivion/2ed61afd06003949a59f0bfec7281cfb80814e1e/app/src/main/res/mipmap-xhdpi/ic_notification.png


--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xhdpi/tv_banner.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bepass-org/oblivion/2ed61afd06003949a59f0bfec7281cfb80814e1e/app/src/main/res/mipmap-xhdpi/tv_banner.png


--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxhdpi/ic_launcher.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bepass-org/oblivion/2ed61afd06003949a59f0bfec7281cfb80814e1e/app/src/main/res/mipmap-xxhdpi/ic_launcher.webp


--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxhdpi/ic_launcher_foreground.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bepass-org/oblivion/2ed61afd06003949a59f0bfec7281cfb80814e1e/app/src/main/res/mipmap-xxhdpi/ic_launcher_foreground.webp


--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bepass-org/oblivion/2ed61afd06003949a59f0bfec7281cfb80814e1e/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.webp


--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxhdpi/ic_notification.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bepass-org/oblivion/2ed61afd06003949a59f0bfec7281cfb80814e1e/app/src/main/res/mipmap-xxhdpi/ic_notification.png


--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxxhdpi/ic_launcher.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bepass-org/oblivion/2ed61afd06003949a59f0bfec7281cfb80814e1e/app/src/main/res/mipmap-xxxhdpi/ic_launcher.webp


--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxxhdpi/ic_launcher_foreground.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bepass-org/oblivion/2ed61afd06003949a59f0bfec7281cfb80814e1e/app/src/main/res/mipmap-xxxhdpi/ic_launcher_foreground.webp


--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bepass-org/oblivion/2ed61afd06003949a59f0bfec7281cfb80814e1e/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.webp


--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxxhdpi/ic_notification.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bepass-org/oblivion/2ed61afd06003949a59f0bfec7281cfb80814e1e/app/src/main/res/mipmap-xxxhdpi/ic_notification.png


--------------------------------------------------------------------------------
/app/src/main/res/resources.properties:
--------------------------------------------------------------------------------
1 | unqualifiedResLocale=en


--------------------------------------------------------------------------------
/app/src/main/res/values-fa/strings.xml:
--------------------------------------------------------------------------------
 1 | <?xml version="1.0" encoding="utf-8"?>
 2 | <resources>
 3 |     <string name="stateText">متصل نیستید</string>
 4 |     <string name="basedOnWarp">بر پایه وارپ</string>
 5 |     <string name="aboutApp">درباره برنامه</string>
 6 |     <string name="aboutAppDesc">"این برنامه با هدف دسترسی به اینترنت آزاد تهیه شده و هرگونه استفاده تجاری از آن مجاز نیست.\n\n\n اینترنت برای همه، یا هیچ‌کس! "</string>
 7 |     <string name="appVersion">نسخه برنامه: 8</string>
 8 |     <string name="logApp">لاگ برنامه</string>
 9 |     <string name="means">یعنی "فراموشی، بی‌خیالی"</string>
10 |     <string name="dontForget">فراموش نکنید!</string>
11 |     <string name="segaro">#سگارو</string>
12 |     <string name="yousef">#یوسف_قبادی</string>
13 |     <string name="slogan">اینترنت برای همه، یا هیچکس</string>
14 |     <string name="blackList">لیست سیاه</string>
15 |     <string name="disabledR">غیرفعال</string>
16 |     <string name="disabledRText">در حالت غیرفعال، ترافیک تمامی برنامه‌ها از VPN عبور می‌کند.</string>
17 |     <string name="enabledR">فعال</string>
18 |     <string name="enabledRText">در حالت فعال، ترافیک برنامه‌های انتخابی از VPN عبور نمی‌کند.</string>
19 |     <string name="showSystemAppsText">نمایش برنامه‌های سیستمی</string>
20 |     <string name="settingsText">تنظیمات</string>
21 |     <string name="endpointText">اندپوینت</string>
22 |     <string name="endpointTextDesc">ترکیبی از IP یا نام دامنه، به‌همراه پورت</string>
23 |     <string name="portTunText">پورت تونل</string>
24 |     <string name="portTunTextDesc">تعیین پورت تونل برنامه</string>
25 |     <string name="blackListTextDesc">تعیین کنید چه برنامه‌هایی از VPN استفاده نکنند</string>
26 |     <string name="connectFromLanText">اتصال از LAN</string>
27 |     <string name="connectFromLanTextDesc">امکان اتصال سایر دستگاه‌های شبکه</string>
28 |     <string name="psiphonText">سایفون</string>
29 |     <string name="psiphonTextDesc">فعال‌سازی سایفون</string>
30 |     <string name="chooseText">انتخاب کشور</string>
31 |     <string name="chooseTextDesc">کشوری که از آن به اینترنت متصل می‌شوید</string>
32 |     <string name="licenseText">لایسنس</string>
33 |     <string name="licenseTextDesc">اگر لایسنس دارید (هر لایسنس 2x می‌شود)</string>
34 |     <string name="goolText">گول</string>
35 |     <string name="goolTextDesc">فعال‌سازی Warp In Warp</string>
36 |     <string name="editSheetEndpoint">تغییر مقدار Endpoint</string>
37 |     <string name="cancel">انصراف</string>
38 |     <string name="update">به‌روزرسانی</string>
39 |     <string name="notConnected">متصل نیستید</string>
40 |     <string name="connecting">در حال اتصال…</string>
41 |     <string name="connected">اتصال برقرار شد</string>
42 |     <string name="batteryOpL">غیرفعال‌سازی بهینه‌سازی باتری</string>
43 |     <string name="batteryOpLText">غیرفعال‌سازی بهینه‌سازی باتری برای تجربه بهتر</string>
44 |     <string name="dialBtText">برای اطمینان از عملکرد صحیح برنامه، لطفاً بهینه‌سازی باتری برای این برنامه را غیرفعال کنید.</string>
45 |     <string name="goToSettings">به تنظیمات بروید</string>
46 |     <string name="copytoclip">کپی کردن لاگ به کلیپ‌بورد</string>
47 |     <string name="turn_on_dark_mode">حالت تاریک</string>
48 |     <string name="turn_on_dark_mode_desc">اعمال کردن تم تاریک</string>
49 |     <string name="endpointTypeText">نوع نقطه اندپوینت</string>
50 |     <string name="endpointTypeTextDesc">برای یافتن IP نقطه اندپوینت استفاده می‌شود</string>
51 |     <string name="copied_to_clipboard">کپی شد به کلیپ بورد</string>
52 |     <string name="title">عنوان</string>
53 |     <string name="content">اندپوینت</string>
54 |     <string name="save">ذخیره</string>
55 |     <string name="saved_endpoints">نقاط دسترسی ذخیره شده</string>
56 |     <string name="select_language">انتخاب زبان</string>
57 |     <string name="resetAppTextDesc">بازنشانی برنامه به تنظیمات پیش‌فرض</string>
58 |     <string name="resetAppText">بازنشانی</string>
59 |     <string name="proxy_mode">حالت پراکسی</string>
60 |     <string name="running_in_proxy_mode_not_vpn">در حال اجرا در حالت پراکسی، نه VPN</string>
61 |     <string name="reset_to_default_endpoint">بازنشانی به نقطه پیش‌فرض</string>
62 |     <string-array name="countries">
63 |         <item>استرالیا</item>
64 |         <item>اتریش</item>
65 |         <item>بلژیک</item>
66 |         <item>بلغارستان</item>
67 |         <item>کانادا</item>
68 |         <item>کرواسی</item>
69 |         <item>چک</item>
70 |         <item>دانمارک</item>
71 |         <item>استونی</item>
72 |         <item>فنلاند</item>
73 |         <item>فرانسه</item>
74 |         <item>آلمان</item>
75 |         <item>مجارستان</item>
76 |         <item>هند</item>
77 |         <item>ایرلند</item>
78 |         <item>ایتالیا</item>
79 |         <item>ژاپن</item>
80 |         <item>لتونی</item>
81 |         <item>هلند</item>
82 |         <item>نروژ</item>
83 |         <item>لهستان</item>
84 |         <item>پرتغال</item>
85 |         <item>رومانی</item>
86 |         <item>صربستان</item>
87 |         <item>سنگاپور</item>
88 |         <item>اسلواکی</item>
89 |         <item>اسپانیا</item>
90 |         <item>سوئد</item>
91 |         <item>سوئیس</item>
92 |         <item>بریتانیا</item>
93 |         <item>ایالات متحده</item>
94 |     </string-array>
95 |     <string name="splashText">با تلاش #یوسف_قبادی و ده‌ها نفر از فعالان شناخته‌شده یا ناشناس، به‌منظور دسترسی آزاد مردم به اینترنت ...</string>
96 | </resources>
97 | 


--------------------------------------------------------------------------------
/app/src/main/res/values-night/colors.xml:
--------------------------------------------------------------------------------
 1 | <?xml version="1.0" encoding="utf-8"?>
 2 | <resources>
 3 |     <color name="primary">#ffa200</color>
 4 | 
 5 |     <color name="black">#5E5E5E</color>
 6 |     <color name="white">#FFFFFFFF</color>
 7 |     <color name="dark">#1C202C</color>
 8 | 
 9 |     <color name="background">#1C202C</color>
10 |     <color name="text_color">#FFFFFFFF</color>
11 |     <color name="icon_color">#FFFFFFFF</color>
12 |     <color name="subtitle_color">#7B8D9D</color>
13 |     <color name="button_color">#ffa200</color>
14 |     <color name="gray">#D7D7D7</color>
15 |     <color name="status_bar_color">#1C202C</color>
16 |     <color name="dark_gray">#383A45</color>
17 | </resources>


--------------------------------------------------------------------------------
/app/src/main/res/values-ru/strings.xml:
--------------------------------------------------------------------------------
 1 | <?xml version="1.0" encoding="utf-8"?>
 2 | <resources>
 3 |     <string name="stateText">Не подключен</string>
 4 |     <string name="basedOnWarp">Основано на Warp</string>
 5 |     <string name="aboutApp">О приложении</string>
 6 |     <string name="aboutAppDesc">"Это приложение предназначено для свободного доступа к интернету, и любое коммерческое использование запрещено.\n\n\n Интернет для всех или ни для кого!"</string>
 7 |     <string name="appVersion">Версия приложения: 8</string>
 8 |     <string name="logApp">Журнал приложения</string>
 9 |     <string name="means" formatted="true">Означает \"неведение, незнание\"</string>
10 |     <string name="dontForget">Не забудьте!</string>
11 |     <string name="segaro">#Segaro</string>
12 |     <string name="yousef">#Yousef_Ghobadi</string>
13 |     <string name="slogan">Интернет для всех или ни для кого</string>
14 |     <string name="blackList">Черный список</string>
15 |     <string name="disabledR">Отключено</string>
16 |     <string name="disabledRText">В режиме отключения весь трафик приложений проходит через VPN.</string>
17 |     <string name="enabledR">Включено</string>
18 |     <string name="enabledRText">В режиме включения трафик выбранных приложений не проходит через VPN.</string>
19 |     <string name="showSystemAppsText">Показать системные приложения</string>
20 |     <string name="settingsText">Настройки</string>
21 |     <string name="endpointText">Конечная точка</string>
22 |     <string name="endpointTextDesc">Комбинация IP или доменного имени с портом</string>
23 |     <string name="portTunText">Порт туннеля</string>
24 |     <string name="portTunTextDesc">Укажите порт туннеля для приложения</string>
25 |     <string name="blackListTextDesc">Укажите, какие приложения не должны использовать VPN</string>
26 |     <string name="connectFromLanText">Подключение через LAN</string>
27 |     <string name="connectFromLanTextDesc">Возможность подключения других сетевых устройств</string>
28 |     <string name="psiphonText">Psiphon</string>
29 |     <string name="psiphonTextDesc">Активировать Psiphon</string>
30 |     <string name="chooseText">Выбрать страну</string>
31 |     <string name="chooseTextDesc">Страна для подключения к интернету</string>
32 |     <string name="licenseText">Лицензия</string>
33 |     <string name="licenseTextDesc">Если у вас есть лицензия (каждая лицензия удваивается)</string>
34 |     <string name="goolText">Gool</string>
35 |     <string name="goolTextDesc">Активировать Warp в Warp</string>
36 |     <string name="editSheetEndpoint">Изменить значение конечной точки</string>
37 |     <string name="cancel">Отмена</string>
38 |     <string name="update">Обновить</string>
39 |     <string name="notConnected">Не подключено</string>
40 |     <string name="connecting">Подключение…</string>
41 |     <string name="connected">Подключено</string>
42 |     <string name="batteryOpL">Отключить оптимизацию батареи</string>
43 |     <string name="batteryOpLText">Отключение оптимизации батареи для лучшего опыта</string>
44 |     <string name="dialBtText">Чтобы приложение работало правильно, отключите оптимизацию батареи для этого приложения.</string>
45 |     <string name="goToSettings">Перейти к настройкам</string>
46 |     <string name="copytoclip">Скопировать лог в буфер обмена</string>
47 |     <string name="endpointTypeText">Тип конечной точки</string>
48 |     <string name="endpointTypeTextDesc">Используется для нахождения IP конечной точки</string>
49 |     <string name="turn_on_dark_mode">Включить темный режим</string>
50 |     <string name="turn_on_dark_mode_desc">включить темный режим</string>
51 |     <string name="copied_to_clipboard">Скопировано в буфер обмена</string>
52 |     <string name="title">Заголовок</string>
53 |     <string name="content">Конечная точка</string>
54 |     <string name="save">Сохранить</string>
55 |     <string name="saved_endpoints">Сохраненные точки доступа</string>
56 |     <string name="select_language">Выберите язык</string>
57 |     <string name="resetAppTextDesc">Сбросить настройки приложения на умолчания</string>
58 |     <string name="resetAppText">Сброс</string>
59 |     <string name="proxy_mode">Режим прокси</string>
60 |     <string name="running_in_proxy_mode_not_vpn">Работает в режиме прокси, а не VPN</string>
61 |     <string name="reset_to_default_endpoint">Сбросить на стандартную конечную точку</string>
62 |     <string-array name="countries">
63 |         <item>Австралия</item>
64 |         <item>Австрия</item>
65 |         <item>Бельгия</item>
66 |         <item>Болгария</item>
67 |         <item>Канада</item>
68 |         <item>Хорватия</item>
69 |         <item>Чехия</item>
70 |         <item>Дания</item>
71 |         <item>Эстония</item>
72 |         <item>Финляндия</item>
73 |         <item>Франция</item>
74 |         <item>Германия</item>
75 |         <item>Венгрия</item>
76 |         <item>Индия</item>
77 |         <item>Ирландия</item>
78 |         <item>Италия</item>
79 |         <item>Япония</item>
80 |         <item>Латвия</item>
81 |         <item>Нидерланды</item>
82 |         <item>Норвегия</item>
83 |         <item>Польша</item>
84 |         <item>Португалия</item>
85 |         <item>Румыния</item>
86 |         <item>Сербия</item>
87 |         <item>Сингапур</item>
88 |         <item>Словакия</item>
89 |         <item>Испания</item>
90 |         <item>Швеция</item>
91 |         <item>Швейцария</item>
92 |         <item>Великобритания</item>
93 |         <item>Соединенные Штаты</item>
94 |     </string-array>
95 |     <string name="splashText">С усилиями #Юсеф_Кобади и десятков известных или анонимных активистов с целью обеспечения свободного доступа людей в интернет…</string>
96 | </resources>
97 | 


--------------------------------------------------------------------------------
/app/src/main/res/values-tr/strings.xml:
--------------------------------------------------------------------------------
 1 | <?xml version="1.0" encoding="utf-8"?>
 2 | <resources>
 3 |     <string name="stateText">Bağlı Değil</string>
 4 |     <string name="basedOnWarp">Warp\'a Dayalı</string>
 5 |     <string name="aboutApp">Uygulama Hakkında</string>
 6 |     <string name="aboutAppDesc">"Bu uygulama internete özgürce erişim sağlamak için tasarlanmıştır ve ticari kullanımı yasaktır.\n\n\n İnternet herkes için ya da hiç kimse için!"</string>
 7 |     <string name="appVersion">Uygulama Sürümü: 8</string>
 8 |     <string name="logApp">Uygulama Günlüğü</string>
 9 |     <string name="means" formatted="true">"bilgisizlik, cehalet" anlamına gelir</string>
10 |     <string name="dontForget">Unutma!</string>
11 |     <string name="segaro">#Segaro</string>
12 |     <string name="yousef">#Yousef_Ghobadi</string>
13 |     <string name="slogan">İnternet Herkes İçin, Ya Da Hiç Kimse İçin</string>
14 |     <string name="blackList">Kara Liste</string>
15 |     <string name="disabledR">Devre Dışı</string>
16 |     <string name="disabledRText">Devre dışı modda, tüm uygulamaların trafiği VPN üzerinden geçer.</string>
17 |     <string name="enabledR">Etkin</string>
18 |     <string name="enabledRText">Etkin modda, seçilen uygulamaların trafiği VPN üzerinden geçmez.</string>
19 |     <string name="showSystemAppsText">Sistem Uygulamalarını Göster</string>
20 |     <string name="settingsText">Ayarlar</string>
21 |     <string name="endpointText">Uç Nokta</string>
22 |     <string name="endpointTextDesc">IP veya alan adı ile birlikte port kombinasyonu</string>
23 |     <string name="portTunText">Tünel Portu</string>
24 |     <string name="portTunTextDesc">Uygulama için tünel portunu belirleyin</string>
25 |     <string name="blackListTextDesc">Hangi uygulamaların VPN kullanmayacağını belirleyin</string>
26 |     <string name="connectFromLanText">LAN\'dan Bağlan</string>
27 |     <string name="connectFromLanTextDesc">Diğer ağ cihazlarına bağlanma yeteneği</string>
28 |     <string name="psiphonText">Psiphon</string>
29 |     <string name="psiphonTextDesc">Psiphon\'u Etkinleştir</string>
30 |     <string name="chooseText">Ülke Seç</string>
31 |     <string name="chooseTextDesc">İnternete bağlanmak için ülke seçimi</string>
32 |     <string name="licenseText">Lisans</string>
33 |     <string name="licenseTextDesc">Bir lisansınız varsa (her lisans iki katına çıkar)</string>
34 |     <string name="goolText">Gool</string>
35 |     <string name="goolTextDesc">Warp İçinde Warp\'ı Etkinleştir</string>
36 |     <string name="editSheetEndpoint">Uç Nokta Değerini Değiştir</string>
37 |     <string name="cancel">İptal</string>
38 |     <string name="update">Güncelle</string>
39 |     <string name="notConnected">Bağlı Değil</string>
40 |     <string name="connecting">Bağlanıyor…</string>
41 |     <string name="connected">Bağlandı</string>
42 |     <string name="batteryOpL">Pil Optimizasyonunu Devre Dışı Bırak</string>
43 |     <string name="batteryOpLText">Daha iyi bir deneyim için pil optimizasyonunu devre dışı bırakma</string>
44 |     <string name="dialBtText">Uygulamanın düzgün çalışmasını sağlamak için, lütfen bu uygulama için pil optimizasyonunu devre dışı bırakın.</string>
45 |     <string name="goToSettings">Ayarlar\'a Git</string>
46 |     <string name="copytoclip">Günlüğü panoya kopyala</string>
47 |     <string name="endpointTypeText">Uç Nokta Türü</string>
48 |     <string name="endpointTypeTextDesc">Uç nokta IP\'sini bulmak için kullanılır</string>
49 |     <string name="turn_on_dark_mode">Karanlık Modu Aç</string>
50 |     <string name="turn_on_dark_mode_desc">karanlık modu aç</string>
51 |     <string name="copied_to_clipboard">Panoya kopyalandı</string>
52 |     <string name="title">Başlık</string>
53 |     <string name="content">Uç Nokta</string>
54 |     <string name="save">Kaydet</string>
55 |     <string name="saved_endpoints">Kaydedilen Uç Noktalar</string>
56 |     <string name="select_language">Dil Seçin</string>
57 |     <string name="resetAppTextDesc">Uygulamayı varsayılana sıfırla</string>
58 |     <string name="resetAppText">Sıfırla</string>
59 |     <string name="proxy_mode">Proxy Modu</string>
60 |     <string name="running_in_proxy_mode_not_vpn">Proxy modunda çalışıyor, VPN değil</string>
61 |     <string name="reset_to_default_endpoint">Varsayılan Uç Noktaya Sıfırla</string>
62 |     <string-array name="countries">
63 |         <item>Avustralya</item>
64 |         <item>Avusturya</item>
65 |         <item>Belçika</item>
66 |         <item>Bulgaristan</item>
67 |         <item>Kanada</item>
68 |         <item>Hırvatistan</item>
69 |         <item>Çekya</item>
70 |         <item>Danimarka</item>
71 |         <item>Estonya</item>
72 |         <item>Finlandiya</item>
73 |         <item>Fransa</item>
74 |         <item>Almanya</item>
75 |         <item>Macaristan</item>
76 |         <item>Hindistan</item>
77 |         <item>İrlanda</item>
78 |         <item>İtalya</item>
79 |         <item>Japonya</item>
80 |         <item>Letonya</item>
81 |         <item>Hollanda</item>
82 |         <item>Norveç</item>
83 |         <item>Polonya</item>
84 |         <item>Portekiz</item>
85 |         <item>Romanya</item>
86 |         <item>Sırbistan</item>
87 |         <item>Singapur</item>
88 |         <item>Slovakya</item>
89 |         <item>İspanya</item>
90 |         <item>İsveç</item>
91 |         <item>İsviçre</item>
92 |         <item>Birleşik Krallık</item>
93 |         <item>Amerika Birleşik Devletleri</item>
94 |     </string-array>
95 |     <string name="splashText">#Yusuf_Ghobadi ve tanınmış ya da anonim aktivistlerin çabalarıyla, halkın internete özgür erişimini sağlamak amacıyla…</string>
96 | </resources>
97 | 


--------------------------------------------------------------------------------
/app/src/main/res/values-zh/strings.xml:
--------------------------------------------------------------------------------
 1 | <?xml version="1.0" encoding="utf-8"?>
 2 | <resources>
 3 |     <string name="stateText">未连接</string>
 4 |     <string name="basedOnWarp">基于Warp</string>
 5 |     <string name="aboutApp">关于应用</string>
 6 |     <string name="aboutAppDesc">"此应用程序旨在自由访问互联网,任何商业用途均被禁止。\n\n\n 互联网为所有人,或者无人!"</string>
 7 |     <string name="appVersion">应用版本:8</string>
 8 |     <string name="logApp">应用日志</string>
 9 |     <string name="means" formatted="true">意思是“无意识,无知”</string>
10 |     <string name="dontForget">不要忘记!</string>
11 |     <string name="segaro">#Segaro</string>
12 |     <string name="yousef">#Yousef_Ghobadi</string>
13 |     <string name="slogan">互联网为所有人,或者无人</string>
14 |     <string name="blackList">黑名单</string>
15 |     <string name="disabledR">全局模式</string>
16 |     <string name="disabledRText">在全局模式下,所有应用的流量都通过VPN。</string>
17 |     <string name="enabledR">绕行模式</string>
18 |     <string name="enabledRText">在绕行模式下,所选应用的流量不会经过VPN。</string>
19 |     <string name="showSystemAppsText">显示系统应用</string>
20 |     <string name="settingsText">设置</string>
21 |     <string name="endpointText">端点</string>
22 |     <string name="endpointTextDesc">IP或域名与端口的组合</string>
23 |     <string name="portTunText">隧道端口</string>
24 |     <string name="portTunTextDesc">指定应用程序的隧道端口</string>
25 |     <string name="blackListTextDesc">指定不应使用VPN的应用程序</string>
26 |     <string name="connectFromLanText">允许来自局域网的连接</string>
27 |     <string name="connectFromLanTextDesc">允许局域网中的其他设备使用此代理</string>
28 |     <string name="psiphonText">赛风</string>
29 |     <string name="psiphonTextDesc">激活赛风</string>
30 |     <string name="chooseText">选择国家</string>
31 |     <string name="chooseTextDesc">连接到互联网的国家</string>
32 |     <string name="licenseText">许可证</string>
33 |     <string name="licenseTextDesc">如果您有许可证(每个许可证都会加倍)</string>
34 |     <string name="goolText">Gool</string>
35 |     <string name="goolTextDesc">激活Warp中的Warp(通过Warp连接Warp)</string>
36 |     <string name="editSheetEndpoint">更改端点值</string>
37 |     <string name="cancel">取消</string>
38 |     <string name="update">更新</string>
39 |     <string name="notConnected">未连接</string>
40 |     <string name="connecting">正在连接…</string>
41 |     <string name="connected">已连接</string>
42 |     <string name="batteryOpL">关闭电池优化</string>
43 |     <string name="batteryOpLText">为了更好的体验,关闭电池优化</string>
44 |     <string name="dialBtText">为了确保应用程序正常运行,请为此应用程序关闭电池优化。</string>
45 |     <string name="goToSettings">前往设置</string>
46 |     <string name="copytoclip">复制日志到剪贴板</string>
47 |     <string name="turn_on_dark_mode">深色模式</string>
48 |     <string name="turn_on_dark_mode_desc">申请 深色模式</string>
49 |     <string name="endpointTypeText">端点类型</string>
50 |     <string name="endpointTypeTextDesc">用于查找终点IP</string>
51 |     <string name="copied_to_clipboard">复制到剪贴板</string>
52 |     <string name="title">标题</string>
53 |     <string name="content">端点</string>
54 |     <string name="save">保存</string>
55 |     <string name="saved_endpoints">已保存的端点</string>
56 |     <string name="resetAppTextDesc">将应用程序重置为默认设置</string>
57 |     <string name="resetAppText">重置</string>
58 |     <string name="proxy_mode">代理模式</string>
59 |     <string name="running_in_proxy_mode_not_vpn">以代理模式运行,而不是VPN</string>
60 |     <string name="reset_to_default_endpoint">重置为默认端点</string>
61 |     <string-array name="countries">
62 |         <item>澳大利亚</item>
63 |         <item>奥地利</item>
64 |         <item>比利时</item>
65 |         <item>保加利亚</item>
66 |         <item>加拿大</item>
67 |         <item>克罗地亚</item>
68 |         <item>捷克</item>
69 |         <item>丹麦</item>
70 |         <item>爱沙尼亚</item>
71 |         <item>芬兰</item>
72 |         <item>法国</item>
73 |         <item>德国</item>
74 |         <item>匈牙利</item>
75 |         <item>印度</item>
76 |         <item>爱尔兰</item>
77 |         <item>意大利</item>
78 |         <item>日本</item>
79 |         <item>拉脱维亚</item>
80 |         <item>荷兰</item>
81 |         <item>挪威</item>
82 |         <item>波兰</item>
83 |         <item>葡萄牙</item>
84 |         <item>罗马尼亚</item>
85 |         <item>塞尔维亚</item>
86 |         <item>新加坡</item>
87 |         <item>斯洛伐克</item>
88 |         <item>西班牙</item>
89 |         <item>瑞典</item>
90 |         <item>瑞士</item>
91 |         <item>英国</item>
92 |         <item>美国</item>
93 |     </string-array>
94 |     <string name="select_language">选择语言</string>
95 |     <string name="splashText">在#尤瑟夫_科巴迪和几十位知名或匿名活动家的努力下,旨在为人民提供自由上网的机会…</string>
96 | 
97 | </resources>
98 | 


--------------------------------------------------------------------------------
/app/src/main/res/values/attrs.xml:
--------------------------------------------------------------------------------
1 | <?xml version="1.0" encoding="utf-8"?>
2 | <resources>
3 | 
4 | 
5 |     <declare-styleable name="Icon">
6 |         <attr name="icon_color" format="color" />
7 |     </declare-styleable>
8 | </resources>


--------------------------------------------------------------------------------
/app/src/main/res/values/colors.xml:
--------------------------------------------------------------------------------
 1 | <?xml version="1.0" encoding="utf-8"?>
 2 | <resources>
 3 |     <color name="primary">#ffa200</color>
 4 | 
 5 |     <color name="black">#333333</color>
 6 |     <color name="white">#FFFFFFFF</color>
 7 |     <color name="dark">#1C202C</color>
 8 | 
 9 |     <color name="background">#FFFFFFFF</color>
10 |     <color name="text_color">#1C202C</color>
11 |     <color name="icon_color">#1C202C</color>
12 |     <color name="subtitle_color">#7B8D9D</color>
13 |     <color name="button_color">#ffa200</color>
14 |     <color name="gray">#D7D7D7</color>
15 |     <color name="status_bar_color">#FFFFFFFF</color>
16 |     <color name="dark_gray">#AAAAAAAA</color>
17 | </resources>
18 | 


--------------------------------------------------------------------------------
/app/src/main/res/values/ic_launcher_background.xml:
--------------------------------------------------------------------------------
1 | <?xml version="1.0" encoding="utf-8"?>
2 | <resources>
3 |   <color name="ic_launcher_background">#963E3E</color>
4 | </resources>
5 | 


--------------------------------------------------------------------------------
/app/src/main/res/values/styles.xml:
--------------------------------------------------------------------------------
 1 | <?xml version="1.0" encoding="utf-8"?>
 2 | <resources>
 3 |     <style name="CustomProgressBar" parent="Widget.AppCompat.ProgressBar">
 4 |         <item name="android:indeterminateDrawable">@drawable/custom_progress_drawable</item>
 5 |     </style>
 6 |     <style name="basedOnTheme" parent="@android:style/Theme.Material">
 7 |         <item name="android:tint">@color/tint_selector</item>
 8 |     </style>
 9 | </resources>
10 | 


--------------------------------------------------------------------------------
/app/src/main/res/values/themes.xml:
--------------------------------------------------------------------------------
 1 | <?xml version="1.0" encoding="utf-8"?>
 2 | <resources>
 3 | 
 4 |   <style name="Theme.OblivionUI" parent="Theme.AppCompat.Light.NoActionBar">
 5 |     <item name="bottomSheetDialogTheme">@style/CustomBottomSheetDialog</item>
 6 |   </style>
 7 | 
 8 |   <!-- Light theme -->
 9 |   <style name="Theme.OblivionUI.Light" parent="Theme.AppCompat.Light">
10 |     <item name="android:windowBackground">@drawable/background_gradient</item>
11 |     <item name="android:background">@drawable/background_gradient</item>
12 |   </style>
13 | 
14 |   <!-- Dark theme -->
15 |   <style name="Theme.MyApp.Dark" parent="Theme.AppCompat.DayNight">
16 |     <item name="android:windowBackground">@color/background</item>
17 |     <item name="android:background">@color/background</item>
18 |   </style>
19 | 
20 |   <style name="CustomBottomSheetDialog" parent="ThemeOverlay.MaterialComponents.BottomSheetDialog">
21 |     <item name="android:windowIsFloating">false</item>
22 |     <item name="android:windowSoftInputMode">adjustResize</item>
23 |     <item name="bottomSheetStyle">@style/CustomBottomSheet</item>
24 |   </style>
25 | 
26 |   <style name="CustomBottomSheet" parent="Widget.MaterialComponents.BottomSheet.Modal">` <item
27 |       name="backgroundTint">@android:color/transparent</item>
28 |   </style>
29 | 
30 |     <style name="circleImageView" parent="">
31 |         <item name="cornerFamily">rounded</item>
32 |         <item name="cornerSize">50%</item>
33 |     </style>
34 | 
35 | </resources>
36 | 


--------------------------------------------------------------------------------
/app/src/main/res/xml/backup_rules.xml:
--------------------------------------------------------------------------------
 1 | <?xml version="1.0" encoding="utf-8"?><!--
 2 |    Sample backup rules file; uncomment and customize as necessary.
 3 |    See https://developer.android.com/guide/topics/data/autobackup
 4 |    for details.
 5 |    Note: This file is ignored for devices older that API 31
 6 |    See https://developer.android.com/about/versions/12/backup-restore
 7 | -->
 8 | <full-backup-content>
 9 |   <!--
10 |    <include domain="sharedpref" path="."/>
11 |    <exclude domain="sharedpref" path="device.xml"/>
12 | -->
13 | </full-backup-content>
14 | 


--------------------------------------------------------------------------------
/app/src/main/res/xml/data_extraction_rules.xml:
--------------------------------------------------------------------------------
 1 | <?xml version="1.0" encoding="utf-8"?><!--
 2 |    Sample data extraction rules file; uncomment and customize as necessary.
 3 |    See https://developer.android.com/about/versions/12/backup-restore#xml-changes
 4 |    for details.
 5 | -->
 6 | <data-extraction-rules>
 7 |   <cloud-backup>
 8 |     <!-- TODO: Use <include> and <exclude> to control what is backed up.
 9 |         <include .../>
10 |         <exclude .../>
11 |         -->
12 |   </cloud-backup>
13 |   <!--
14 |     <device-transfer>
15 |         <include .../>
16 |         <exclude .../>
17 |     </device-transfer>
18 |     -->
19 | </data-extraction-rules>
20 | 


--------------------------------------------------------------------------------
/app/src/main/res/xml/network_security_config.xml:
--------------------------------------------------------------------------------
1 | <?xml version="1.0" encoding="utf-8"?>
2 | <network-security-config>
3 |     <domain-config cleartextTrafficPermitted="true">
4 |         <domain includeSubdomains="true">ip-api.com</domain>
5 |     </domain-config>
6 | </network-security-config>


--------------------------------------------------------------------------------
/build.gradle:
--------------------------------------------------------------------------------
1 | // Top-level build file where you can add configuration options common to all sub-projects/modules.
2 | plugins {
3 |     id 'com.android.application' version '8.8.0' apply false
4 |     id 'org.jetbrains.kotlin.android' version '1.8.10' apply false
5 | }
6 | 


--------------------------------------------------------------------------------
/devshell.nix:
--------------------------------------------------------------------------------
 1 | { pkgs }:
 2 | 
 3 | with pkgs;
 4 | 
 5 | # Configure your development environment.
 6 | #
 7 | # Documentation: https://github.com/numtide/devshell
 8 | devshell.mkShell {
 9 |   name = "oblivion";
10 |   motd = ''
11 |     Entered the Android app development environment.
12 |   '';
13 |   env = [
14 |     {
15 |       name = "ANDROID_HOME";
16 |       value = "${android-sdk}/share/android-sdk";
17 |     }
18 |     {
19 |       name = "ANDROID_SDK_ROOT";
20 |       value = "${android-sdk}/share/android-sdk";
21 |     }
22 |     {
23 |       name = "JAVA_HOME";
24 |       value = jdk11.home;
25 |     }
26 |     {
27 |       name = "GOBIN";
28 |       eval = "$HOME/go/bin";
29 |     }
30 |     {
31 |       name = "PATH";
32 |       eval = "$HOME/go/bin:$PATH";
33 |     }
34 |   ];
35 |   packages = [
36 |     android-studio
37 |     android-sdk
38 |     gradle
39 |     jdk11
40 |     go_1_22
41 |   ];
42 | }
43 | 


--------------------------------------------------------------------------------
/flake.nix:
--------------------------------------------------------------------------------
 1 | {
 2 |   description = "oblivion";
 3 | 
 4 |   inputs = {
 5 |     nixpkgs.url = "nixpkgs/nixos-unstable";
 6 |     devshell.url = "github:numtide/devshell";
 7 |     flake-utils.url = "github:numtide/flake-utils";
 8 |     android.url = "github:tadfisher/android-nixpkgs";
 9 |   };
10 | 
11 |   outputs = { self, nixpkgs, devshell, flake-utils, android }:
12 |     {
13 |       overlay = final: prev: {
14 |         inherit (self.packages.${final.system}) android-sdk android-studio;
15 |       };
16 |     }
17 |     //
18 |     flake-utils.lib.eachSystem [ "aarch64-darwin" "x86_64-darwin" "x86_64-linux" ] (system:
19 |       let
20 |         inherit (nixpkgs) lib;
21 |         pkgs = import nixpkgs {
22 |           inherit system;
23 |           config.allowUnfree = true;
24 |           overlays = [
25 |             devshell.overlays.default
26 |             self.overlay
27 |           ];
28 |         };
29 |       in
30 |       {
31 |         packages = {
32 |           android-sdk = android.sdk.${system} (sdkPkgs: with sdkPkgs; [
33 |             # Useful packages for building and testing.
34 |             build-tools-34-0-0
35 |             cmdline-tools-latest
36 |             emulator
37 |             platform-tools
38 |             platforms-android-34
39 | 
40 |             # Other useful packages for a development environment.
41 |             ndk-26-1-10909125
42 |             # skiaparser-3
43 |             # sources-android-34
44 |           ]
45 |           ++ lib.optionals (system == "aarch64-darwin") [
46 |             # system-images-android-34-google-apis-arm64-v8a
47 |             # system-images-android-34-google-apis-playstore-arm64-v8a
48 |           ]
49 |           ++ lib.optionals (system == "x86_64-darwin" || system == "x86_64-linux") [
50 |             system-images-android-31-google-apis-x86-64
51 |             system-images-android-31-google-apis-playstore-x86-64
52 |             system-images-android-32-google-apis-x86-64
53 |             system-images-android-32-google-apis-playstore-x86-64
54 |             system-images-android-33-google-apis-x86-64
55 |             system-images-android-33-google-apis-playstore-x86-64
56 |             system-images-android-34-google-apis-x86-64
57 |             system-images-android-34-google-apis-playstore-x86-64
58 |           ]);
59 |         } // lib.optionalAttrs (system == "x86_64-linux") {
60 |           # Android Studio in nixpkgs is currently packaged for x86_64-linux only.
61 |           android-studio = pkgs.androidStudioPackages.stable;
62 |           # android-studio = pkgs.androidStudioPackages.beta;
63 |           # android-studio = pkgs.androidStudioPackages.preview;
64 |           # android-studio = pkgs.androidStudioPackage.canary;
65 |         };
66 | 
67 |         devShell = import ./devshell.nix { inherit pkgs; };
68 |       }
69 |     );
70 | }
71 | 


--------------------------------------------------------------------------------
/gradle.properties:
--------------------------------------------------------------------------------
 1 | # Project-wide Gradle settings.
 2 | # IDE (e.g. Android Studio) users:
 3 | # Gradle settings configured through the IDE *will override*
 4 | # any settings specified in this file.
 5 | # For more details on how to configure your build environment visit
 6 | # http://www.gradle.org/docs/current/userguide/build_environment.html
 7 | # Specifies the JVM arguments used for the daemon process.
 8 | # The setting is particularly useful for tweaking memory settings.
 9 | org.gradle.jvmargs=-Xmx2048m -Dfile.encoding=UTF-8
10 | # When configured, Gradle will run in incubating parallel mode.
11 | # This option should only be used with decoupled projects. More details, visit
12 | # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
13 | # org.gradle.parallel=true
14 | # AndroidX package structure to make it clearer which packages are bundled with the
15 | # Android operating system, and which are packaged with your app's APK
16 | # https://developer.android.com/topic/libraries/support-library/androidx-rn
17 | android.useAndroidX=true
18 | # Kotlin code style for this project: "official" or "obsolete":
19 | kotlin.code.style=official
20 | # Enables namespacing of each library's R class so that its R class includes only the
21 | # resources declared in the library itself and none from the library's dependencies,
22 | # thereby reducing the size of the R class for that library
23 | android.nonTransitiveRClass=true
24 | android.enableJetifier=true
25 | 


--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bepass-org/oblivion/2ed61afd06003949a59f0bfec7281cfb80814e1e/gradle/wrapper/gradle-wrapper.jar


--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.properties:
--------------------------------------------------------------------------------
1 | #Wed Feb 07 16:52:07 IRST 2024
2 | distributionBase=GRADLE_USER_HOME
3 | distributionPath=wrapper/dists
4 | distributionUrl=https\://services.gradle.org/distributions/gradle-8.10.2-bin.zip
5 | zipStoreBase=GRADLE_USER_HOME
6 | zipStorePath=wrapper/dists
7 | 


--------------------------------------------------------------------------------
/gradlew.bat:
--------------------------------------------------------------------------------
 1 | @rem
 2 | @rem Copyright 2015 the original author or authors.
 3 | @rem
 4 | @rem Licensed under the Apache License, Version 2.0 (the "License");
 5 | @rem you may not use this file except in compliance with the License.
 6 | @rem You may obtain a copy of the License at
 7 | @rem
 8 | @rem      https://www.apache.org/licenses/LICENSE-2.0
 9 | @rem
10 | @rem Unless required by applicable law or agreed to in writing, software
11 | @rem distributed under the License is distributed on an "AS IS" BASIS,
12 | @rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | @rem See the License for the specific language governing permissions and
14 | @rem limitations under the License.
15 | @rem
16 | 
17 | @if "%DEBUG%" == "" @echo off
18 | @rem ##########################################################################
19 | @rem
20 | @rem  Gradle startup script for Windows
21 | @rem
22 | @rem ##########################################################################
23 | 
24 | @rem Set local scope for the variables with windows NT shell
25 | if "%OS%"=="Windows_NT" setlocal
26 | 
27 | set DIRNAME=%~dp0
28 | if "%DIRNAME%" == "" set DIRNAME=.
29 | set APP_BASE_NAME=%~n0
30 | set APP_HOME=%DIRNAME%
31 | 
32 | @rem Resolve any "." and ".." in APP_HOME to make it shorter.
33 | for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi
34 | 
35 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
36 | set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m"
37 | 
38 | @rem Find java.exe
39 | if defined JAVA_HOME goto findJavaFromJavaHome
40 | 
41 | set JAVA_EXE=java.exe
42 | %JAVA_EXE% -version >NUL 2>&1
43 | if "%ERRORLEVEL%" == "0" goto execute
44 | 
45 | echo.
46 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
47 | echo.
48 | echo Please set the JAVA_HOME variable in your environment to match the
49 | echo location of your Java installation.
50 | 
51 | goto fail
52 | 
53 | :findJavaFromJavaHome
54 | set JAVA_HOME=%JAVA_HOME:"=%
55 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe
56 | 
57 | if exist "%JAVA_EXE%" goto execute
58 | 
59 | echo.
60 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
61 | echo.
62 | echo Please set the JAVA_HOME variable in your environment to match the
63 | echo location of your Java installation.
64 | 
65 | goto fail
66 | 
67 | :execute
68 | @rem Setup the command line
69 | 
70 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
71 | 
72 | 
73 | @rem Execute Gradle
74 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %*
75 | 
76 | :end
77 | @rem End local scope for the variables with windows NT shell
78 | if "%ERRORLEVEL%"=="0" goto mainEnd
79 | 
80 | :fail
81 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
82 | rem the _cmd.exe /c_ return code!
83 | if  not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
84 | exit /b 1
85 | 
86 | :mainEnd
87 | if "%OS%"=="Windows_NT" endlocal
88 | 
89 | :omega
90 | 


--------------------------------------------------------------------------------
/media/oblivion3.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bepass-org/oblivion/2ed61afd06003949a59f0bfec7281cfb80814e1e/media/oblivion3.jpg


--------------------------------------------------------------------------------
/settings.gradle:
--------------------------------------------------------------------------------
 1 | pluginManagement {
 2 |     repositories {
 3 |         google()
 4 |         mavenCentral()
 5 |         gradlePluginPortal()
 6 |     }
 7 | }
 8 | dependencyResolutionManagement {
 9 |     repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS)
10 |     repositories {
11 |         google()
12 |         mavenCentral()
13 |         maven { url 'https://jitpack.io' }
14 |     }
15 | }
16 | 
17 | rootProject.name = "Oblivion"
18 | include ':app'
19 | 


--------------------------------------------------------------------------------
/tun2socks/README.md:
--------------------------------------------------------------------------------
1 | # How To build?
2 | 
3 | ## Go Version "MUST be exactly go 1.22" because of psiphon library then you can run
4 | 
5 | ```sh
6 | go run golang.org/x/mobile/cmd/gomobile init
7 | go run golang.org/x/mobile/cmd/gomobile bind -ldflags="-w -s" -target=android -androidapi=21 -o=tun2socks.aar .
8 | ```
9 | 


--------------------------------------------------------------------------------
/tun2socks/lwip/lwip.go:
--------------------------------------------------------------------------------
  1 | package lwip
  2 | 
  3 | import (
  4 | 	"errors"
  5 | 	"io"
  6 | 	"net"
  7 | 	"os"
  8 | 	"time"
  9 | 
 10 | 	"github.com/eycorsican/go-tun2socks/common/dns/cache"
 11 | 	"github.com/eycorsican/go-tun2socks/common/dns/fakedns"
 12 | 	"github.com/eycorsican/go-tun2socks/common/log"
 13 | 	"github.com/eycorsican/go-tun2socks/component/pool"
 14 | 	"github.com/eycorsican/go-tun2socks/component/runner"
 15 | 	"github.com/eycorsican/go-tun2socks/core"
 16 | 	"github.com/eycorsican/go-tun2socks/proxy/socks"
 17 | 
 18 | 	"github.com/songgao/water"
 19 | )
 20 | 
 21 | type Tun2socksStartOptions struct {
 22 | 	TunFd        int
 23 | 	Socks5Server string
 24 | 	FakeIPRange  string
 25 | 	MTU          int
 26 | 	EnableIPv6   bool
 27 | 	AllowLan     bool
 28 | }
 29 | 
 30 | var (
 31 | 	lwipWriter          io.Writer
 32 | 	lwipStack           core.LWIPStack
 33 | 	mtuUsed             int
 34 | 	lwipTUNDataPipeTask *runner.Task
 35 | 	tunDev              *water.Interface
 36 | )
 37 | 
 38 | // Stop stop it
 39 | func Stop() {
 40 | 	log.Infof("enter stop")
 41 | 	log.Infof("begin close tun")
 42 | 	err := tunDev.Close()
 43 | 	if err != nil {
 44 | 		log.Infof("close tun(Stop func): %v", err)
 45 | 	}
 46 | 	if lwipTUNDataPipeTask.Running() {
 47 | 		log.Infof("send stop lwipTUNDataPipeTask sig")
 48 | 		lwipTUNDataPipeTask.Stop()
 49 | 		log.Infof("lwipTUNDataPipeTask stop sig sent")
 50 | 		<-lwipTUNDataPipeTask.StopChan()
 51 | 	} else {
 52 | 		log.Infof("lwipTUNDataPipeTask already stopped")
 53 | 	}
 54 | 
 55 | 	log.Infof("begin close lwipStack")
 56 | 	lwipStack.Close(core.DELAY)
 57 | }
 58 | 
 59 | // hack to receive tunfd
 60 | func openTunDevice(tunFd int) (*water.Interface, error) {
 61 | 	file := os.NewFile(uintptr(tunFd), "tun") // dummy file path name since we already got the fd
 62 | 	tunDev = &water.Interface{
 63 | 		ReadWriteCloser: file,
 64 | 	}
 65 | 	return tunDev, nil
 66 | }
 67 | 
 68 | // Start sets up lwIP stack, starts a Tun2socks instance
 69 | func Start(opt *Tun2socksStartOptions) int {
 70 | 
 71 | 	mtuUsed = opt.MTU
 72 | 	var err error
 73 | 	tunDev, err = openTunDevice(opt.TunFd)
 74 | 	if err != nil {
 75 | 		log.Fatalf("failed to open tun device: %v", err)
 76 | 	}
 77 | 	// handle previous lwIP stack
 78 | 	if lwipStack != nil {
 79 | 		log.Infof("begin close previous lwipStack")
 80 | 		lwipStack.Close(core.INSTANT)
 81 | 	} else {
 82 | 		log.Infof("do NOT have to close previous lwipStack")
 83 | 	}
 84 | 
 85 | 	// Setup the lwIP stack.
 86 | 	lwipStack = core.NewLWIPStack(opt.EnableIPv6, opt.AllowLan)
 87 | 	lwipWriter = lwipStack.(io.Writer)
 88 | 
 89 | 	// Register tun2socks connection handlers.
 90 | 	proxyAddr, err := net.ResolveTCPAddr("tcp", opt.Socks5Server)
 91 | 	proxyHost := proxyAddr.IP.String()
 92 | 	proxyPort := uint16(proxyAddr.Port)
 93 | 	if err != nil {
 94 | 		log.Infof("invalid proxy server address: %v", err)
 95 | 		return -1
 96 | 	}
 97 | 	cacheDNS := cache.NewSimpleDnsCache()
 98 | 	if opt.FakeIPRange != "" {
 99 | 		_, ipnet, err := net.ParseCIDR(opt.FakeIPRange)
100 | 		if err != nil {
101 | 			log.Fatalf("failed to parse fake ip range %v", opt.FakeIPRange)
102 | 		}
103 | 		fakeDNS := fakedns.NewFakeDNS(ipnet, 3000)
104 | 		core.RegisterTCPConnHandler(socks.NewTCPHandler(proxyHost, proxyPort, fakeDNS))
105 | 		core.RegisterUDPConnHandler(socks.NewUDPHandler(proxyHost, proxyPort, 30*time.Second, cacheDNS, fakeDNS))
106 | 	} else {
107 | 		core.RegisterTCPConnHandler(socks.NewTCPHandler(proxyHost, proxyPort, nil))
108 | 		core.RegisterUDPConnHandler(socks.NewUDPHandler(proxyHost, proxyPort, 30*time.Second, cacheDNS, nil))
109 | 	}
110 | 
111 | 	// Register an output callback to write packets output from lwip stack to tun
112 | 	// device, output function should be set before input any packets.
113 | 	core.RegisterOutputFn(func(data []byte) (int, error) {
114 | 		// lwip -> tun
115 | 		return tunDev.Write(data)
116 | 	})
117 | 
118 | 	if lwipTUNDataPipeTask != nil && lwipTUNDataPipeTask.Running() {
119 | 		log.Infof("stop previous lwipTUNDataPipeTask sig")
120 | 		lwipTUNDataPipeTask.Stop()
121 | 		log.Infof("previous lwipTUNDataPipeTask stop sig sent")
122 | 		<-lwipTUNDataPipeTask.StopChan()
123 | 	} else {
124 | 		log.Infof("previous lwipTUNDataPipeTask already stopped or never being started")
125 | 	}
126 | 
127 | 	lwipTUNDataPipeTask = runner.Go(func(shouldStop runner.S) error {
128 | 		// do setup
129 | 		// defer func(){
130 | 		//	// do teardown
131 | 		// }()
132 | 		zeroErr := errors.New("no error")
133 | 		maxErrorTimes := 20
134 | 		for {
135 | 			// NOTE: the for-loop here will retry when we find errors,
136 | 			//       it gives up when we reach exceeded error times.
137 | 			// do some work here
138 | 
139 | 			// tun -> lwip
140 | 			buf := pool.NewBytes(pool.BufSize)
141 | 			// NOTE: In general, when transfering the data, it blocks here until either end becomes invalid
142 | 			_, err := io.CopyBuffer(lwipWriter, tunDev, buf)
143 | 			pool.FreeBytes(buf)
144 | 			if err != nil {
145 | 				maxErrorTimes--
146 | 				log.Infof("copying data failed: %v", err)
147 | 			}
148 | 			if shouldStop() {
149 | 				log.Infof("got DataPipe stop signal")
150 | 				break
151 | 			}
152 | 			if maxErrorTimes <= 0 {
153 | 				log.Infof("lwipTUNDataPipeTask returns due to exceeded error times")
154 | 				return err
155 | 			}
156 | 		}
157 | 		log.Infof("exit DataPipe loop")
158 | 		return zeroErr // any errors?
159 | 	})
160 | 
161 | 	log.Infof("Running tun2socks")
162 | 
163 | 	return 0
164 | }
165 | 


--------------------------------------------------------------------------------
/tun2socks/tools.go:
--------------------------------------------------------------------------------
 1 | //go:build tools
 2 | // +build tools
 3 | 
 4 | package tun2socks
 5 | 
 6 | import (
 7 | 	_ "golang.org/x/mobile/bind"
 8 | 	_ "golang.org/x/mobile/cmd/gomobile"
 9 | )
10 | 


--------------------------------------------------------------------------------
/tun2socks/tun2socks.go:
--------------------------------------------------------------------------------
  1 | package tun2socks
  2 | 
  3 | import (
  4 | 	"bufio"
  5 | 	"context"
  6 | 	"fmt"
  7 | 	"io"
  8 | 	"log/slog"
  9 | 	"net/netip"
 10 | 	"os"
 11 | 	"os/signal"
 12 | 	"strings"
 13 | 	"sync"
 14 | 	"syscall"
 15 | 	"time"
 16 | 	"tun2socks/lwip"
 17 | 
 18 | 	"github.com/bepass-org/warp-plus/app"
 19 | 	"github.com/bepass-org/warp-plus/wiresocks"
 20 | 	L "github.com/xjasonlyu/tun2socks/v2/log"
 21 | )
 22 | 
 23 | // Variables to hold flag values.
 24 | var (
 25 | 	logMessages []string
 26 | 	mu          sync.Mutex
 27 | 	ctx         context.Context
 28 | 	cancelFunc  context.CancelFunc
 29 | 	l           *slog.Logger
 30 | )
 31 | 
 32 | type StartOptions struct {
 33 | 	TunFd          int
 34 | 	Path           string
 35 | 	FakeIPRange    string
 36 | 	Verbose        bool
 37 | 	BindAddress    string
 38 | 	Endpoint       string
 39 | 	License        string
 40 | 	Country        string
 41 | 	PsiphonEnabled bool
 42 | 	Gool           bool
 43 | 	DNS            string
 44 | 	EndpointType   int
 45 | }
 46 | 
 47 | type logWriter struct{}
 48 | 
 49 | func (writer logWriter) Write(bytes []byte) (int, error) {
 50 | 	mu.Lock()
 51 | 	defer mu.Unlock()
 52 | 	logMessages = append(logMessages, string(bytes))
 53 | 	return len(bytes), nil
 54 | }
 55 | 
 56 | func Start(opt *StartOptions) {
 57 | 	ctx, cancelFunc = signal.NotifyContext(context.Background(), os.Interrupt, syscall.SIGTERM)
 58 | 
 59 | 	if err := os.Chdir(opt.Path); err != nil {
 60 | 		l.Error("error changing to 'main' directory", "error", err.Error())
 61 | 		os.Exit(1)
 62 | 	}
 63 | 
 64 | 	logger := logWriter{}
 65 | 
 66 | 	lOpts := slog.HandlerOptions{
 67 | 		Level: func() slog.Level {
 68 | 			if opt.Verbose {
 69 | 				return slog.LevelDebug
 70 | 			}
 71 | 			return slog.LevelInfo
 72 | 		}(),
 73 | 		ReplaceAttr: func(groups []string, a slog.Attr) slog.Attr {
 74 | 			if (a.Key == slog.TimeKey || a.Key == slog.LevelKey) && len(groups) == 0 {
 75 | 				return slog.Attr{} // remove excess keys
 76 | 			}
 77 | 			return a
 78 | 		},
 79 | 	}
 80 | 
 81 | 	l = slog.New(slog.NewTextHandler(logger, &lOpts))
 82 | 	r, w, _ := os.Pipe()
 83 | 	os.Stdout = w
 84 | 	os.Stderr = w
 85 | 	L.SetLevel(L.DebugLevel)
 86 | 	L.SetOutput(logger)
 87 | 
 88 | 	go func(reader io.Reader) {
 89 | 		scanner := bufio.NewScanner(reader)
 90 | 		for scanner.Scan() {
 91 | 			logger.Write([]byte(scanner.Text()))
 92 | 		}
 93 | 		if err := scanner.Err(); err != nil {
 94 | 			fmt.Fprintln(os.Stderr, "There was an error with the scanner", err)
 95 | 		}
 96 | 	}(r)
 97 | 	l.Info(fmt.Sprintf("%+v", *opt))
 98 | 	var scanOpts *wiresocks.ScanOptions
 99 | 	if opt.Endpoint == "" {
100 | 		scanOpts = &wiresocks.ScanOptions{
101 | 			V4:     false,
102 | 			V6:     false,
103 | 			MaxRTT: 1500 * time.Millisecond,
104 | 		}
105 | 		switch opt.EndpointType {
106 | 		case 0:
107 | 			scanOpts.V4 = true
108 | 			scanOpts.V6 = true
109 | 		case 1:
110 | 			scanOpts.V4 = true
111 | 		case 2:
112 | 			scanOpts.V6 = true
113 | 		}
114 | 	}
115 | 
116 | 	var psiphonOpts *app.PsiphonOptions
117 | 	if opt.PsiphonEnabled {
118 | 		psiphonOpts = &app.PsiphonOptions{
119 | 			Country: opt.Country,
120 | 		}
121 | 	}
122 | 
123 | 	err := app.RunWarp(ctx, l, app.WarpOptions{
124 | 		Bind:     netip.MustParseAddrPort(opt.BindAddress),
125 | 		DnsAddr:  netip.MustParseAddr(opt.DNS),
126 | 		Endpoint: opt.Endpoint,
127 | 		License:  opt.License,
128 | 		Psiphon:  psiphonOpts,
129 | 		Gool:     opt.Gool,
130 | 		Scan:     scanOpts,
131 | 		TestURL:  "http://connectivity.cloudflareclient.com/cdn-cgi/trace",
132 | 	})
133 | 	if err != nil {
134 | 		l.Error(err.Error())
135 | 		os.Exit(1)
136 | 	}
137 | 
138 | 	tun2socksStartOptions := &lwip.Tun2socksStartOptions{
139 | 		TunFd:        opt.TunFd,
140 | 		Socks5Server: strings.Replace(opt.BindAddress, "0.0.0.0", "127.0.0.1", -1),
141 | 		FakeIPRange:  "24.0.0.0/8",
142 | 		MTU:          0,
143 | 		EnableIPv6:   true,
144 | 		AllowLan:     true,
145 | 	}
146 | 	if ret := lwip.Start(tun2socksStartOptions); ret != 0 {
147 | 		l.Error("failed to start LWIP")
148 | 		os.Exit(1)
149 | 	}
150 | 
151 | 	go func() {
152 | 		<-ctx.Done()
153 | 		lwip.Stop()
154 | 
155 | 		l.Info("server shut down gracefully")
156 | 	}()
157 | }
158 | 
159 | func Stop() {
160 | 	if cancelFunc != nil {
161 | 		cancelFunc()
162 | 	}
163 | }
164 | 
165 | func GetLogMessages() string {
166 | 	mu.Lock()
167 | 	defer mu.Unlock()
168 | 	if len(logMessages) == 0 {
169 | 		return ""
170 | 	}
171 | 	logs := strings.Join(logMessages, "\n")
172 | 	logMessages = nil // Clear logMessages for better memory management
173 | 	return logs
174 | }
175 | 


--------------------------------------------------------------------------------