├── .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 |  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'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 | --------------------------------------------------------------------------------