Initial commit to public repo
2
.gitattributes
vendored
Normal file
@@ -0,0 +1,2 @@
|
||||
# Auto detect text files and perform LF normalization
|
||||
* text=auto
|
||||
15
.gitignore
vendored
Normal file
@@ -0,0 +1,15 @@
|
||||
*.iml
|
||||
.gradle
|
||||
/local.properties
|
||||
/.idea/caches
|
||||
/.idea/libraries
|
||||
/.idea/modules.xml
|
||||
/.idea/workspace.xml
|
||||
/.idea/navEditor.xml
|
||||
/.idea/assetWizardSettings.xml
|
||||
.DS_Store
|
||||
/build
|
||||
/captures
|
||||
.externalNativeBuild
|
||||
.cxx
|
||||
local.properties
|
||||
400
README.md
Normal file
@@ -0,0 +1,400 @@
|
||||
# Proxidize Android - Create 5G/4G Mobile Proxies on Android Phones
|
||||
|
||||
Proxidize Android Legacy is an Android application that enables anyone to make 4G or 5G mobile proxies using their Android phones without the need of anything else. Just download the app, hit connect, and your mobile proxy will be automatically generated.
|
||||
|
||||
Proxidize created Proxidize Android as a proof of concept for Proxidize MPM (Mobile Proxy Maker). The app accomplished its purpose, but was eventually taken down from the Google Play Store for reasons mentioned below.
|
||||
|
||||
With the rise of Russian & Chinese Proxidize MPM copycat apps, and after seeing the damage these can cause to the community of proxy users with the recent scandal, we decided to open source this app to protect the users from falling prey to any botnet apps. Further read: [Proxidize copycats, a story of greed & international crim syndicates](https://proxidize.com/blog/proxidize-copycats-a-story-of-greed-international-crime-syndicates/)
|
||||
|
||||
Proxidize Android Legacy is the predecessor of the upcoming Proxidize Portable application which will solve all the shortcomings of this app.
|
||||
|
||||
|
||||
<div align="center"> </br><a href="https://proxidize.com/">
|
||||
<img src="https://i.imgur.com/HkPj7Fx.png" height="auto"/>
|
||||
</a>
|
||||
</br></br></br></div>
|
||||
|
||||
<div align="center">
|
||||
|
||||
<a href="#contributing"><img src="https://img.shields.io/badge/PRs-welcome-brightgreen.svg" /></a>
|
||||
<a href="#license"><img src="https://img.shields.io/badge/license-Apache%202-blue" /></a>
|
||||
</div>
|
||||
|
||||
|
||||
---
|
||||
|
||||
## What Is Proxidize?
|
||||
|
||||
Proxidize is a multi-national effort started by a team of engineers to democratize access to web data & automation. We are currently in phase #1 which is building the proxy infrastructure required to build the full project.
|
||||
|
||||
Read the Proxidize manifesto: https://proxidize.com/manifesto/
|
||||
|
||||
|
||||
<div align="center"> <a href="https://proxidize.com/">
|
||||
<img src="https://i.imgur.com/3FEWrk5.png" height="auto"/>
|
||||
</a>
|
||||
</div>
|
||||
|
||||
<div align="center">
|
||||
<h2>Proxidize</h2>
|
||||
<a href="#installing-proxidize-android-legacy">Create Mobile Proxies</a>
|
||||
<span> • </span>
|
||||
<a href="#rotationchanging-the-ip-how-to-change-mobile-proxy-ip-address-using-airplane-mode">IP Rotation</a>
|
||||
<span> • </span>
|
||||
<a href="https://proxidize.com/">Website</a>
|
||||
<span> • </span>
|
||||
<a href="https://proxidize.com/docs">Docs</a>
|
||||
<span> • </span>
|
||||
<a href="https://proxidize.com/blog">Blog</a>
|
||||
<span> • </span>
|
||||
<a href="https://twitter.com/proxidizehq">Twitter</a>
|
||||
<span> • </span>
|
||||
<a href="#proxidize-portable">Proxidize Portable</a>
|
||||
<br />
|
||||
<hr />
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
---
|
||||
## Table of Content
|
||||
|
||||
- [Proxidize Android - Create 5G/4G Mobile Proxies on Android Phones](#proxidize-android---create-5g4g-mobile-proxies-on-android-phones)
|
||||
* [What Is Proxidize?](#what-is-proxidize)
|
||||
* [Features of Proxidize Android Legacy](#features-of-proxidize-android-legacy)
|
||||
* [How It Works & Architecture](#how-it-works--architecture)
|
||||
* [Proxidize Android Legacy vs Proxidize Mobile Proxy Maker](#proxidize-android-legacy-vs-proxidize-mobile-proxy-maker)
|
||||
* [Installing Proxidize Android Legacy](#installing-proxidize-android-legacy)
|
||||
* [Using the Proxy](#using-the-proxy)
|
||||
* [Rotation/Changing the IP (How to Change Mobile Proxy IP Address Using Airplane Mode)](#rotationchanging-the-ip-how-to-change-mobile-proxy-ip-address-using-airplane-mode)
|
||||
* [Supported Android Versions & Devices](#supported-android-versions--devices)
|
||||
* [Using the App Without Connecting to the Tunneling Server First](#using-the-app-without-connecting-to-the-tunneling-server-first)
|
||||
* [Reporting Issues](#reporting-issues)
|
||||
* [Contributing](#contributing)
|
||||
* [Deploying Your Own Server](#deploying-your-own-server)
|
||||
* [FAQ](#faq)
|
||||
* [Credits](#credits)
|
||||
* [Proxidize Portable](#proxidize-portable)
|
||||
* [License](#license)
|
||||
|
||||
|
||||
|
||||
---
|
||||
|
||||
## Features of Proxidize Android Legacy
|
||||
|
||||
- Create A Mobile or Residential HTTP proxy on Android, MacOS or Windows devices.
|
||||
- Connect to mobile data while using the app to generate a mobile proxy.
|
||||
- Connect to WiFi while using the app to generate a residential proxy.
|
||||
- Rotate the IP manually or automatically via 3rd parties
|
||||
- Add custom tunneling servers
|
||||
|
||||
---
|
||||
|
||||
## How It Works & Architecture
|
||||
|
||||
Proxidize Android Legacy works by establishing a connection to a tunneling server via reverse proxies and then launching a local HTTP proxy server. This makes the proxy accessible from anywhere on the web, as the tunneling server handles the port forwarding and routing.
|
||||
|
||||

|
||||
|
||||
The application will select a random port between ```10000``` and ```60000```, use it connect to the client and then create a proxy server based on the random port along with a randomly generated username and password.
|
||||
|
||||
|
||||
---
|
||||
## Proxidize Android Legacy vs Proxidize Mobile Proxy Maker
|
||||
|
||||
This app is not a replacement for Proxidize Mobile Proxy Maker, but a proof of concept. You can use this app at a small scale for personal projects, but once you need a commercial-grade solution, you'll need Proxidize MPM for the following reasons:
|
||||
|
||||
- Such apps will always be naturally unreliable due to underlying infrastructure being deisgned mainly for IoT devices and not proxies.
|
||||
- Low speeds. Since both incoming and outgoing connections are passing through the same network interface, the speed you get will be a fifth of the mobile speed.
|
||||
- Difficult to manage at scale. It takes a 10 minutes to set up a 20-modem kit from Proxidize, but setting up 20 phones will take a full day if not more.
|
||||
|
||||
---
|
||||
|
||||
## Installing Proxidize Android Legacy
|
||||
|
||||

|
||||
|
||||
### How to use on Android: (Create 5G or 4G Mobile Proxies on Android)
|
||||
|
||||
- Download Proxidize Android Legacy APK File
|
||||
- Install the APK on your device
|
||||
- Open the app and press "Connect".
|
||||
- Copy the proxy and you can use it anywhere.
|
||||
|
||||
|
||||
### How to Use on Windows MacOS (Create 5G or 4G Mobile Proxies on Windows)
|
||||
|
||||
- Download any Android emulator such as BlueStacks
|
||||
- Download Proxidize Android Legacy APK file inside the emulator (Open this page from the emulator and download the APK)
|
||||
- Install the APK on your device
|
||||
- Open the app and press "Connect".
|
||||
- Copy the proxy and you can use it anywhere.
|
||||
|
||||
---
|
||||
|
||||
## Using the Proxy
|
||||
|
||||
Format:
|
||||
```
|
||||
IP:Port:Username:Password
|
||||
```
|
||||
|
||||
Example:
|
||||
```
|
||||
1.1.1.1:1565:abc:xyz
|
||||
```
|
||||
|
||||
Explained:
|
||||
```
|
||||
IP or Hostanme: 1.1.1.1
|
||||
Port: 1565
|
||||
Userrname: abc
|
||||
Password: xyz
|
||||
```
|
||||
---
|
||||
## Rotation/Changing the IP (How to Change Mobile Proxy IP Address Using Airplane Mode)
|
||||
|
||||
You can rotate the IP by having any macro app automatically toggle airplane mode on and off.
|
||||
|
||||
### Automatically Changing the IP Address:
|
||||
|
||||

|
||||
|
||||
To automatically change the IP address, you can use a macros app such as MacroDroid which we'll use here.
|
||||
|
||||
- Download MacroDroid from the Google Play Store https://play.google.com/store/apps/details?id=com.arlosoft.macrodroid
|
||||
- Create a new macro and name it "Proxidize Android IP Change"
|
||||
- Go to Settings > Assistant Settings > Default assistant app > Set "MacroDroid" to be the default assistant app
|
||||
- Add trigger "Regular Interval" and set it to whatever interval you want the IP to change over.
|
||||
- Add Actions:
|
||||
- Toggle airplane mode on
|
||||
- Wait 3 seconds
|
||||
- Toggle airplane mode off
|
||||
- Save the macro (edited)
|
||||
|
||||
And now your IP will automatically change every set amount of time as you specified in the interval.
|
||||
|
||||
|
||||
### Changing the IP Manually:
|
||||
|
||||
- Make sure you are connected to mobile data
|
||||
- Toggle airplane mode on and off
|
||||
- You will now have a new public IP address
|
||||
|
||||
---
|
||||
## Supported Android Versions & Devices
|
||||
|
||||
Proxidize Android Legacy supports all ```armeabi-v7a``` running ```Android 6.0``` to ```Android 12```
|
||||
|
||||
Supported Android API from ```API 23``` to ```API 31```.
|
||||
|
||||
Tested devices:
|
||||
```
|
||||
Samsung A Series
|
||||
Samsung S Series
|
||||
Samsung M Series
|
||||
Samsung Note Series
|
||||
Google Pixel
|
||||
OnePlus
|
||||
```
|
||||
---
|
||||
|
||||
## Deploying Your Own Server
|
||||
|
||||
- Create a new server on any host. Make sure you're on a public network with all the ports publicly accessible.
|
||||
- Edit configuration file to add your server information.
|
||||
- Edit ```CUSTOM SERVER``` button fields to add your new server.
|
||||
|
||||
### Example:
|
||||
|
||||
- Server IP = ```5.5.5.5```
|
||||
|
||||
- Make sure the server is ```x86-64``` or ```AMD64``` running ```Ubuntu 20.04```
|
||||
|
||||
- SSH into your server
|
||||
|
||||
``` ssh username@5.5.5.5```
|
||||
|
||||
- Clone this repo
|
||||
|
||||
``` git clone THISREPO.git ```
|
||||
|
||||
- Edit the server.ini file to add an authentication token
|
||||
|
||||
``` vi``` or ```nano ./server.ini ```
|
||||
|
||||
- Add the following info, replacing ```PORT``` and ```TOKEN``` with your own values. Keep the port value as ```2000``` unless you have a reason to change it.
|
||||
|
||||
```
|
||||
[common]
|
||||
bind_port = PORT
|
||||
authentication_method=token
|
||||
token = TOKEN
|
||||
```
|
||||
|
||||
```TOKEN``` is used to authenticate which clients are allowed to connect to this server. It can be any random set of characters such as ```12345678```.
|
||||
|
||||
- Start the server
|
||||
|
||||
``` setsid ./server -c ./server.ini &```
|
||||
|
||||
```setsid``` is used to keep the process alive after you close the terminal.
|
||||
|
||||
- Add the new server information to your application by using the "CUSTOM SERVER" button.
|
||||
|
||||
```HOST``` = The new server public IP address. In this example it's ```5.5.5.5```.
|
||||
|
||||
```Binding Port``` = The port your selected.
|
||||
|
||||
```Token``` = The token you selected.
|
||||
|
||||
- Save the details, exit the app and open it again and hit connect. You will now connect to your new tunneling server.
|
||||
|
||||
|
||||
---
|
||||
## Using the App Without Connecting to the Tunneling Server First
|
||||
|
||||
In some cases, you might be able to connect directly to the phone without needing to connect to the tunneling server. The advantage of this is that you won't have to connect to the tunneling server first, which will offer 5-10% higher speeds.
|
||||
|
||||
- Make sure your carrier can give you a dedicated v4 IP. This is very rare and you will need to confirm with the carrier.
|
||||
- Call your carrier and request they forward the ports for you.
|
||||
- Get your public IP address by searching for what's my IP address.
|
||||
- The app is listening on 0.0.0.0 so once you forward the proxy port, just connect to it using your public IP.
|
||||
- You can also do that if you're connected to WiFi, but you'll need to forward the ports on your router.
|
||||
|
||||
|
||||
---
|
||||
|
||||
## Reporting Issues
|
||||
|
||||
### Types of Issues That You Should Report:
|
||||
|
||||
- App keeps crashing on a specific device/Android version.
|
||||
- Bypass battery optimization not working on a specific device/Android version.
|
||||
- App stops working after a while on any
|
||||
- Proxy Refusing Connection web error, even though the port and host are correct.
|
||||
- If you see any of the following errors: 12020, 12033, or 12165.
|
||||
|
||||
### How to Report the Issue:
|
||||
|
||||
- Full description of the issue including screenshots and any error codes
|
||||
- Full device manufacturer & model name. E.g. Samsung SM-A105L
|
||||
- Include a screenshot of the "Software information" page
|
||||
- Full instructions to replicate the issue.
|
||||
|
||||
|
||||
### Any issues unrelated to the app will be closed, such as:
|
||||
|
||||
- I sent 1,000 threads to scrape Amazon and now the IP is banned.
|
||||
- I'm using vanilla puppeteer or Chrome and I keep getting blocked or my proxy is detected.
|
||||
- Any form of 407/authentication error. This means you're not using the right credentials. Refer to format section.
|
||||
- 502 or 504 if you're using rotation. This happens when you're connecting in the middle of a rotation.
|
||||
- Any situation where you're using your own server. (Unless you can replicate the issue when using the default server as well.)
|
||||
|
||||
|
||||
---
|
||||
## Contributing
|
||||
|
||||
This app is no longer maintained by Proxidize, but I (Abed) will be working on it in my free time.
|
||||
|
||||
Things I'll be adding:
|
||||
|
||||
- [x] Supporting Android 12
|
||||
- [x] Add Android wake lock to keep the proxy alive if the screen if off.
|
||||
- [x] Custom server from application.
|
||||
- [ ] Prevent duplicate ports on server.
|
||||
- [ ] Supporting more devices such as Asus, Alcatel, etc.
|
||||
- [ ] Showing the public IP on the app interface.
|
||||
- [ ] Change proxy format.
|
||||
- [ ] IP authentication via ACLs.
|
||||
- [ ] Traffic counters.
|
||||
- [ ] SOCKS proxies.
|
||||
|
||||
If you want to add a new feature, please create an issue first to describe the new feature, as well as the implementation approach. Once a proposal is accepted, create an implementation of the new features and submit it as a pull request. The Go binaries are compiled with ```gomobile``` using FRP.
|
||||
|
||||
---
|
||||
|
||||
|
||||
## FAQ:
|
||||
|
||||
### Why is the app marked as harmful app/malware by Google?
|
||||
|
||||
A few months after publishing the app, Google marked it as harmful/PUP/malware app. I suspect it's because there's some Google watchdog that sniffed the traffic and found something harmful that was being transmitted by some of the users. Or it's possible that the behavior of the traffic being unencrypted and routed to a single server was similar to typical harmful app behavior that come across Google in the Play Store.
|
||||
|
||||
There are also a few AVs that have marked the tunneling client, frp, as a PUP, and it's possible Google Play Store did the same.
|
||||
|
||||
I've made some mitigations against this by changing the binaries to change the hash, but I suspect Google will still mark it as harmful by reading the strings, so you will need to disable Play Protect, otherwise, it'll get automatically deleted.
|
||||
|
||||
### My proxy isn't working with ```Proxy Refusing Connection``` error?
|
||||
|
||||
Please exit the app and start it again. There's a very small chance you used an already used port.
|
||||
|
||||
### My proxy stopped working after it used to work, can you help?
|
||||
|
||||
Exit the app and start it again. If it still doesn't work, make sure the app is still running on your device. Then please tweet [@Proxidizehq](https://twitter.com/proxidizehq) and we'll take a look.
|
||||
|
||||
### Why is my proxy slow?
|
||||
|
||||
The app uses reverse proxies created via websockets route to forwarding facing proxies. This technology is slow, unreliable and there's nothing I can do about it with the limited time that I have to work on this project. Apps based on this specific tunneling technology were created for simple IoT use cases, and not for pushing full bandwidth or proxies.
|
||||
|
||||
The Proxidize team is working on an entirely new app called **Proxidize Portable**, which will address all the short comings of this app using proprietary technology.
|
||||
|
||||
Another thing is such apps send both incoming and outgoing traffic from the same device, which means you will always get half the speed that you would normally get when testing the speed directly on your phone. If speed is important, you should use the full Proxidize MPM-OP: https://proxidize.com/
|
||||
|
||||
### Where will this app work?
|
||||
|
||||
This app will work everywhere, unless:
|
||||
- You are in countries that have ISP-level firewalls that block any proxied connections via DPI.
|
||||
- You are behind a corporate firewall that blocks unknown ports.
|
||||
|
||||
### I keep getting a ```407 Error``` or the proxy keeps asking for authentication?
|
||||
|
||||
Make sure you're not mixing the small ```l``` with a capital ```I```.
|
||||
|
||||
---
|
||||
|
||||
## Credits
|
||||
|
||||
Proxidize Android Legacy Credits
|
||||
- Unni from the Proxidize team for creating the Android tunneling client
|
||||
- Muhammad from the Proxidize team for the interface & battery optimization
|
||||
- Frp Tunneling Server
|
||||
- The Squid Foundation
|
||||
|
||||
---
|
||||
|
||||
## Proxidize Portable
|
||||
|
||||
We are currently working on a new application called "Proxidize MPM-Cloud Portable" or Proxidize Portable for short. The new app will address all the deficiencies of this one and will have the following features:
|
||||
|
||||
1. 5-10x higher speeds than Proxidize Android Legacy
|
||||
2. HTTP or SOCKS proxies
|
||||
3. Custom OS Fingerprint
|
||||
4. Send & Receive SMS via interface/API
|
||||
5. Manage all devices from web interface
|
||||
6. Rotate IP manually, every X interval, or via API link.
|
||||
7. Manage unlimited phones via grouping, categories and more.
|
||||
8. Use any server from dozens of countries.
|
||||
9. Custom DNS
|
||||
10. Get 99.99% uptime
|
||||
11. Dual-stacking IPV6/IPV6 support
|
||||
12. Load-balancing between multiple phones.
|
||||
13. Setting multi-phone IP rotation pools.
|
||||
14. And more. Feel free to request anything else.
|
||||
|
||||
---
|
||||
|
||||
## License
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
1
app/.gitignore
vendored
Normal file
@@ -0,0 +1 @@
|
||||
/build
|
||||
59
app/build.gradle
Normal file
@@ -0,0 +1,59 @@
|
||||
plugins {
|
||||
id 'com.android.application'
|
||||
id 'org.jetbrains.kotlin.android'
|
||||
}
|
||||
|
||||
android {
|
||||
compileSdk 32
|
||||
|
||||
defaultConfig {
|
||||
applicationId "com.legacy.android"
|
||||
minSdk 23
|
||||
targetSdk 32
|
||||
versionCode 1
|
||||
versionName "1.0"
|
||||
|
||||
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
|
||||
}
|
||||
|
||||
buildTypes {
|
||||
release {
|
||||
minifyEnabled false
|
||||
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
|
||||
}
|
||||
}
|
||||
buildFeatures {
|
||||
viewBinding true
|
||||
}
|
||||
compileOptions {
|
||||
sourceCompatibility JavaVersion.VERSION_1_8
|
||||
targetCompatibility JavaVersion.VERSION_1_8
|
||||
}
|
||||
kotlinOptions {
|
||||
jvmTarget = '1.8'
|
||||
}
|
||||
}
|
||||
|
||||
dependencies {
|
||||
implementation fileTree(include: ['*.jar'], dir: 'libs')
|
||||
implementation files('libs/connlib.aar')
|
||||
implementation 'androidx.core:core-ktx:1.8.0'
|
||||
implementation 'androidx.appcompat:appcompat:1.4.2'
|
||||
implementation 'com.google.android.material:material:1.6.1'
|
||||
implementation 'androidx.constraintlayout:constraintlayout:2.1.4'
|
||||
testImplementation 'junit:junit:4.13.2'
|
||||
androidTestImplementation 'androidx.test.ext:junit:1.1.3'
|
||||
androidTestImplementation 'androidx.test.espresso:espresso-core:3.4.0'
|
||||
|
||||
|
||||
//data store for liecence
|
||||
implementation "androidx.datastore:datastore-preferences:1.0.0"
|
||||
|
||||
implementation 'androidx.lifecycle:lifecycle-viewmodel-ktx:2.5.0'
|
||||
implementation "androidx.lifecycle:lifecycle-runtime-ktx:2.6.0-alpha01"
|
||||
|
||||
implementation "androidx.fragment:fragment-ktx:1.5.0"
|
||||
implementation "androidx.lifecycle:lifecycle-livedata-ktx:2.6.0-alpha01"
|
||||
|
||||
implementation 'com.google.android.material:material:1.6.1'
|
||||
}
|
||||
BIN
app/libs/connlib-sources.jar
Normal file
BIN
app/libs/connlib.aar
Normal file
21
app/proguard-rules.pro
vendored
Normal file
@@ -0,0 +1,21 @@
|
||||
# Add project specific ProGuard rules here.
|
||||
# You can control the set of applied configuration files using the
|
||||
# proguardFiles setting in build.gradle.
|
||||
#
|
||||
# For more details, see
|
||||
# http://developer.android.com/guide/developing/tools/proguard.html
|
||||
|
||||
# If your project uses WebView with JS, uncomment the following
|
||||
# and specify the fully qualified class name to the JavaScript interface
|
||||
# class:
|
||||
#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
|
||||
# public *;
|
||||
#}
|
||||
|
||||
# Uncomment this to preserve the line number information for
|
||||
# debugging stack traces.
|
||||
#-keepattributes SourceFile,LineNumberTable
|
||||
|
||||
# If you keep the line number information, uncomment this to
|
||||
# hide the original source file name.
|
||||
#-renamesourcefileattribute SourceFile
|
||||
@@ -0,0 +1,24 @@
|
||||
package com.legacy.android
|
||||
|
||||
import androidx.test.platform.app.InstrumentationRegistry
|
||||
import androidx.test.ext.junit.runners.AndroidJUnit4
|
||||
|
||||
import org.junit.Test
|
||||
import org.junit.runner.RunWith
|
||||
|
||||
import org.junit.Assert.*
|
||||
|
||||
/**
|
||||
* Instrumented test, which will execute on an Android device.
|
||||
*
|
||||
* See [testing documentation](http://d.android.com/tools/testing).
|
||||
*/
|
||||
@RunWith(AndroidJUnit4::class)
|
||||
class ExampleInstrumentedTest {
|
||||
@Test
|
||||
fun useAppContext() {
|
||||
// Context of the app under test.
|
||||
val appContext = InstrumentationRegistry.getInstrumentation().targetContext
|
||||
assertEquals("com.legacy.android", appContext.packageName)
|
||||
}
|
||||
}
|
||||
48
app/src/main/AndroidManifest.xml
Normal file
@@ -0,0 +1,48 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
package="com.legacy.android">
|
||||
|
||||
<uses-permission android:name="android.permission.INTERNET" />
|
||||
<uses-permission android:name="android.permission.REQUEST_IGNORE_BATTERY_OPTIMIZATIONS" />
|
||||
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
|
||||
<uses-permission android:name="android.permission.WAKE_LOCK" />
|
||||
|
||||
<application
|
||||
android:name=".MyApplication"
|
||||
android:allowBackup="true"
|
||||
android:dataExtractionRules="@xml/data_extraction_rules"
|
||||
android:fullBackupContent="@xml/backup_rules"
|
||||
android:icon="@mipmap/ic_launcher"
|
||||
android:label="@string/app_name"
|
||||
android:requestLegacyExternalStorage="true"
|
||||
android:roundIcon="@mipmap/ic_launcher"
|
||||
android:supportsRtl="true"
|
||||
android:theme="@style/AppTheme.NoAction"
|
||||
android:usesCleartextTraffic="false"
|
||||
tools:targetApi="31">
|
||||
<activity
|
||||
android:name=".CustomServerActivity"
|
||||
android:exported="false"
|
||||
android:theme="@style/Theme.ProxidizeAndroidLegacy" />
|
||||
|
||||
<service
|
||||
android:name=".NotificationService"
|
||||
android:exported="false" />
|
||||
|
||||
<activity
|
||||
android:name=".LoginActivity"
|
||||
android:exported="false"
|
||||
android:theme="@style/Theme.ProxidizeAndroidLegacy" />
|
||||
<activity
|
||||
android:name=".MainActivity"
|
||||
android:exported="true">
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.MAIN" />
|
||||
|
||||
<category android:name="android.intent.category.LAUNCHER" />
|
||||
</intent-filter>
|
||||
</activity>
|
||||
</application>
|
||||
|
||||
</manifest>
|
||||
0
app/src/main/assets/config.ini
Normal file
0
app/src/main/assets/connection.log
Normal file
61
app/src/main/java/com/legacy/android/CustomServerActivity.kt
Normal file
@@ -0,0 +1,61 @@
|
||||
package com.legacy.android
|
||||
|
||||
import android.os.Bundle
|
||||
import android.widget.Toast
|
||||
import androidx.appcompat.app.AppCompatActivity
|
||||
import androidx.lifecycle.lifecycleScope
|
||||
import com.legacy.android.databinding.ActivityCustomServerBinding
|
||||
import kotlinx.coroutines.delay
|
||||
import kotlinx.coroutines.launch
|
||||
|
||||
class CustomServerActivity : AppCompatActivity() {
|
||||
|
||||
private lateinit var binding: ActivityCustomServerBinding
|
||||
private val preference by lazy { ServerPreference.getInstance(this) }
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
binding = ActivityCustomServerBinding.inflate(layoutInflater)
|
||||
super.onCreate(savedInstanceState)
|
||||
setContentView(binding.root)
|
||||
binding.saveButton.setOnClickListener {
|
||||
if (isClear()) {
|
||||
Toast.makeText(this, "Saving server info", Toast.LENGTH_SHORT).show()
|
||||
lifecycleScope.launch {
|
||||
preference.saveProxyServer(
|
||||
ProxyServer(
|
||||
binding.etHost.text.toString(),
|
||||
binding.etPort.text.toString(),
|
||||
binding.etToken.text.toString()
|
||||
)
|
||||
)
|
||||
finish()
|
||||
}
|
||||
}
|
||||
}
|
||||
binding.resetButton.setOnClickListener {
|
||||
Toast.makeText(this, "Proxy server set to default", Toast.LENGTH_SHORT).show()
|
||||
lifecycleScope.launch {
|
||||
delay(100)
|
||||
preference.clear()
|
||||
finish()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private fun isClear(): Boolean {
|
||||
var clear = true
|
||||
if (binding.etHost.text.isNullOrEmpty()) {
|
||||
binding.etHost.error = "Enter a valid Host"
|
||||
clear = false
|
||||
} else binding.etHost.error = null
|
||||
if (binding.etPort.text.isNullOrEmpty()) {
|
||||
binding.etPort.error = "Enter a valid Port"
|
||||
clear = false
|
||||
} else binding.etPort.error = null
|
||||
if (binding.etToken.text.isNullOrEmpty()) {
|
||||
binding.etToken.error = "Enter a valid token"
|
||||
clear = false
|
||||
} else binding.etToken.error = null
|
||||
return clear
|
||||
}
|
||||
}
|
||||
321
app/src/main/java/com/legacy/android/LoginActivity.kt
Normal file
@@ -0,0 +1,321 @@
|
||||
package com.legacy.android
|
||||
|
||||
import android.annotation.SuppressLint
|
||||
import android.app.AlertDialog
|
||||
import android.app.Notification
|
||||
import android.app.NotificationManager
|
||||
import android.app.PendingIntent
|
||||
import android.app.PendingIntent.FLAG_MUTABLE
|
||||
import android.content.ClipData
|
||||
import android.content.ClipboardManager
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.graphics.BitmapFactory
|
||||
import android.graphics.Color
|
||||
import android.net.Uri
|
||||
import android.os.*
|
||||
import android.provider.Settings
|
||||
import android.text.Html
|
||||
import android.widget.Toast
|
||||
import androidx.appcompat.app.AppCompatActivity
|
||||
import androidx.core.app.NotificationCompat
|
||||
import androidx.core.app.NotificationManagerCompat
|
||||
import androidx.lifecycle.Lifecycle
|
||||
import androidx.lifecycle.lifecycleScope
|
||||
import androidx.lifecycle.repeatOnLifecycle
|
||||
import com.legacy.android.databinding.ActivityLoginBinding
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.flow.collect
|
||||
import kotlinx.coroutines.launch
|
||||
import java.io.*
|
||||
import java.text.SimpleDateFormat
|
||||
import java.util.*
|
||||
import kotlin.system.exitProcess
|
||||
import frpclib.Frpclib as Conn
|
||||
|
||||
|
||||
class LoginActivity : AppCompatActivity() {
|
||||
private var user: String? = null
|
||||
private var pwd: String? = null
|
||||
private var notificationManager: NotificationManagerCompat? = null
|
||||
private val mLabel = "copy"
|
||||
private var mText: String = ""
|
||||
private var mRandomPort = 0
|
||||
|
||||
private var server: ProxyServer = ProxyServer.default()
|
||||
|
||||
private lateinit var binding: ActivityLoginBinding
|
||||
private val preference by lazy { ServerPreference.getInstance(this) }
|
||||
|
||||
@SuppressLint("BatteryLife")
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
binding = ActivityLoginBinding.inflate(layoutInflater)
|
||||
setContentView(binding.root)
|
||||
|
||||
lifecycleScope.launch {
|
||||
repeatOnLifecycle(Lifecycle.State.STARTED){
|
||||
preference.SERVER.collect{
|
||||
server = it
|
||||
}
|
||||
}
|
||||
}
|
||||
notificationManager = NotificationManagerCompat.from(this)
|
||||
val pm = getSystemService(PowerManager::class.java)
|
||||
if (!pm.isIgnoringBatteryOptimizations(packageName)) {
|
||||
val i = Intent(Settings.ACTION_REQUEST_IGNORE_BATTERY_OPTIMIZATIONS)
|
||||
.setData(Uri.parse("package:$packageName"))
|
||||
startActivity(i)
|
||||
}
|
||||
binding.copyButton.setOnClickListener {
|
||||
val clipboard = getSystemService(CLIPBOARD_SERVICE) as ClipboardManager
|
||||
val clip = ClipData.newPlainText(mLabel, mText)
|
||||
clipboard.setPrimaryClip(clip)
|
||||
Toast.makeText(this@LoginActivity, "Copied", Toast.LENGTH_SHORT).show()
|
||||
}
|
||||
|
||||
|
||||
binding.stop.setOnClickListener {
|
||||
AlertDialog.Builder(this@LoginActivity)
|
||||
.setCancelable(false)
|
||||
.setTitle("Confirm Exit")
|
||||
.setMessage("Are you sure, You want to exit")
|
||||
.setPositiveButton("sure") { d, _ ->
|
||||
stopService(Intent(applicationContext, NotificationService::class.java))
|
||||
d.dismiss()
|
||||
Handler(Looper.getMainLooper()).postDelayed({
|
||||
exitProcess(0)
|
||||
}, 100)
|
||||
}.setNegativeButton("NO", null)
|
||||
.create()
|
||||
.show()
|
||||
}
|
||||
binding.connect.setOnClickListener {
|
||||
writeToConfigFile(server)
|
||||
Toast.makeText(this@LoginActivity, "Connecting to proxy server", Toast.LENGTH_LONG)
|
||||
.show()
|
||||
startConnection()
|
||||
Handler(Looper.getMainLooper()).postDelayed({ checkIfPortUsed() }, 3000)
|
||||
}
|
||||
|
||||
binding.customServer.setOnClickListener{
|
||||
startActivity(Intent(this, CustomServerActivity::class.java))
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
private fun checkIfPortUsed(): Boolean {
|
||||
var connectionStatus = true
|
||||
val logfile = File(filesDir, MyApplication.LOGFILE)
|
||||
if (logfile.exists()) {
|
||||
try {
|
||||
val inputStream: InputStream = assets.open(MyApplication.LOGFILE)
|
||||
var line: String? = null
|
||||
val br = BufferedReader(FileReader(logfile))
|
||||
var isFileEmpty = true
|
||||
while ((br.readLine()?.also { line = it }) != null) {
|
||||
isFileEmpty = false
|
||||
if (line?.contains("port already used") == true) {
|
||||
connectionStatus = false
|
||||
break
|
||||
}
|
||||
}
|
||||
if (!connectionStatus) {
|
||||
Toast.makeText(
|
||||
this@LoginActivity,
|
||||
"Port is already used. Try again",
|
||||
Toast.LENGTH_LONG
|
||||
).show()
|
||||
} else if (isFileEmpty) {
|
||||
Toast.makeText(
|
||||
this@LoginActivity,
|
||||
"Not connected. Restart app and connect again",
|
||||
Toast.LENGTH_LONG
|
||||
).show()
|
||||
} else {
|
||||
showConnectionDetails()
|
||||
val bundle = Bundle().also {
|
||||
it.putInt(PORT, mRandomPort)
|
||||
it.putString(USER, user)
|
||||
it.putString(PASS, pwd)
|
||||
}
|
||||
Toast.makeText(this@LoginActivity, "connection success", Toast.LENGTH_LONG)
|
||||
.show()
|
||||
Handler(Looper.getMainLooper()).postDelayed({
|
||||
val sdf = SimpleDateFormat("HH:mm:ss z")
|
||||
val currentTime = sdf.format(Date())
|
||||
val largeIcon = BitmapFactory.decodeResource(resources, R.drawable.logo)
|
||||
val intent1 = Intent(this, NotificationService::class.java)
|
||||
intent1.action = "close_service"
|
||||
var pIntent: PendingIntent? = null
|
||||
pIntent = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
|
||||
PendingIntent.getService(this, 0, intent1, FLAG_MUTABLE)
|
||||
} else PendingIntent.getService(this, 0, intent1, 0)
|
||||
|
||||
val p2Inten = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
|
||||
PendingIntent.getActivity(
|
||||
this,
|
||||
2,
|
||||
Intent(this, LoginActivity::class.java),
|
||||
FLAG_MUTABLE
|
||||
)
|
||||
} else {
|
||||
PendingIntent.getActivity(
|
||||
this,
|
||||
2,
|
||||
Intent(this, LoginActivity::class.java),
|
||||
0
|
||||
)
|
||||
}
|
||||
val notification = NotificationCompat.Builder(
|
||||
applicationContext,
|
||||
MyApplication.channel_1_id
|
||||
)
|
||||
.setSmallIcon(R.drawable.bill)
|
||||
.setLargeIcon(largeIcon)
|
||||
.setStyle(NotificationCompat.BigPictureStyle())
|
||||
.setStyle(NotificationCompat.BigTextStyle())
|
||||
.setContentIntent(p2Inten)
|
||||
.setContentTitle("Connected")
|
||||
.setExtras(bundle)
|
||||
.addAction(
|
||||
NotificationCompat.Action(
|
||||
R.drawable.ic_baseline_close_24,
|
||||
"Close",
|
||||
pIntent
|
||||
)
|
||||
)
|
||||
.setContentText(
|
||||
"You are Connected to (${server.host}:$mRandomPort:$user:$pwd)On time$currentTime"
|
||||
)
|
||||
.setPriority(NotificationCompat.PRIORITY_HIGH)
|
||||
.setCategory(NotificationCompat.CATEGORY_ALARM)
|
||||
.setColor(Color.YELLOW).build()
|
||||
notificationManager?.notify(NOTIFICATION_ID, notification)
|
||||
}, 2000)
|
||||
val servicesIntent = Intent(applicationContext, NotificationService::class.java)
|
||||
servicesIntent.putExtra("stat", "Proxidize Android is running!!")
|
||||
startService(servicesIntent)
|
||||
}
|
||||
br.close()
|
||||
inputStream.close()
|
||||
} catch (e: IOException) {
|
||||
e.printStackTrace()
|
||||
}
|
||||
}
|
||||
return connectionStatus
|
||||
|
||||
}
|
||||
|
||||
override fun onStart() {
|
||||
super.onStart()
|
||||
val notification = getActiveNotification() ?: return
|
||||
val extras = notification.extras
|
||||
pwd = extras.getString(PASS)
|
||||
user = extras.getString(USER)
|
||||
mRandomPort = extras.getInt(PORT)
|
||||
showConnectionDetails()
|
||||
|
||||
}
|
||||
|
||||
private fun showConnectionDetails() {
|
||||
mText = "${server.host}:$mRandomPort:$user:$pwd"
|
||||
val details =
|
||||
"<b>IP</b> : ${server.host}<br><b>Port</b> : $mRandomPort<br><b>Username</b> : $user<br><b>Password</b> : $pwd"
|
||||
binding.connection.text = mText
|
||||
binding.connectionTextView.text = Html.fromHtml(details)
|
||||
binding.connect.text = getString(R.string.connected)
|
||||
}
|
||||
|
||||
private fun startConnection() {
|
||||
CoroutineScope(Dispatchers.IO).launch {
|
||||
Conn.touch()
|
||||
Conn.run("$filesDir/config.ini")
|
||||
}
|
||||
}
|
||||
|
||||
private fun getActiveNotification(): Notification? {
|
||||
val notificationManager =
|
||||
getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
|
||||
val barNotifications = notificationManager.activeNotifications
|
||||
for (notification in barNotifications) {
|
||||
if (notification.id == NOTIFICATION_ID) {
|
||||
return notification.notification
|
||||
}
|
||||
}
|
||||
return null
|
||||
}
|
||||
|
||||
private fun writeToConfigFile(server: ProxyServer) {
|
||||
// re-create connection.log file
|
||||
val logFile = File(filesDir, MyApplication.LOGFILE)
|
||||
if (logFile.exists()) {
|
||||
logFile.delete()
|
||||
}
|
||||
if (!logFile.exists()) {
|
||||
try {
|
||||
logFile.createNewFile()
|
||||
} catch (e: IOException) {
|
||||
e.printStackTrace()
|
||||
}
|
||||
}
|
||||
var out: FileOutputStream? = null
|
||||
val file = File(filesDir, MyApplication.FILENAME)
|
||||
if (file.exists()) {
|
||||
file.delete()
|
||||
}
|
||||
if (!file.exists()) {
|
||||
try {
|
||||
file.createNewFile()
|
||||
} catch (e: IOException) {
|
||||
e.printStackTrace()
|
||||
}
|
||||
}
|
||||
try {
|
||||
out = FileOutputStream(file, true)
|
||||
mRandomPort = getRandomPort()
|
||||
user = getAlphaNumericString()
|
||||
pwd = getAlphaNumericString()
|
||||
out.write("[common]\r\n".toByteArray())
|
||||
out.write("server_addr = ${server.host}\r\n".toByteArray())
|
||||
out.write("server_port = ${server.port}\r\n".toByteArray())
|
||||
out.write("token = ${server.token}\r\n".toByteArray())
|
||||
out.write("admin_addr = 0.0.0.0\r\n".toByteArray())
|
||||
out.write("admin_port = 7400\r\n".toByteArray())
|
||||
out.write("admin_user = admin\r\n".toByteArray())
|
||||
out.write("admin_passwd = admin\r\n".toByteArray())
|
||||
out.write("log_file = ${logFile.absolutePath}\r\n".toByteArray())
|
||||
out.write("log_level = info\r\n".toByteArray())
|
||||
out.write("log_max_days = 3\r\n".toByteArray())
|
||||
out.write("pool_count = 5\r\n".toByteArray())
|
||||
out.write("tcp_mux = true\r\n".toByteArray())
|
||||
out.write("login_fail_exit = true\r\n".toByteArray())
|
||||
out.write("protocol = tcp\r\n".toByteArray())
|
||||
out.write("[android_proxy_$mRandomPort]\r\n".toByteArray())
|
||||
out.write("type=tcp\r\n".toByteArray())
|
||||
out.write("remote_port=$mRandomPort\r\n".toByteArray())
|
||||
out.write("plugin=http_proxy\r\n".toByteArray())
|
||||
out.write("plugin_http_user=$user\r\n".toByteArray())
|
||||
out.write("plugin_http_passwd=$pwd\r\n".toByteArray())
|
||||
} catch (e: IOException) {
|
||||
e.printStackTrace()
|
||||
} finally {
|
||||
try {
|
||||
out?.close()
|
||||
} catch (e: IOException) {
|
||||
e.printStackTrace()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
companion object {
|
||||
const val NOTIFICATION_ID = 20340
|
||||
const val IP = "IP"
|
||||
const val PORT = "PORT"
|
||||
const val USER = "USER"
|
||||
const val PASS = "PASS"
|
||||
}
|
||||
}
|
||||
43
app/src/main/java/com/legacy/android/MainActivity.kt
Normal file
@@ -0,0 +1,43 @@
|
||||
package com.legacy.android
|
||||
|
||||
import android.app.Activity
|
||||
import android.content.Intent
|
||||
import android.os.Bundle
|
||||
import android.os.Handler
|
||||
import android.os.Looper
|
||||
import android.view.animation.Animation
|
||||
import android.view.animation.AnimationUtils
|
||||
import android.widget.ImageView
|
||||
import android.widget.TextView
|
||||
import androidx.appcompat.app.AppCompatActivity
|
||||
|
||||
class MainActivity : Activity() {
|
||||
|
||||
//VARIABLES
|
||||
var tobAnim: Animation? = null
|
||||
var bottomAnim: Animation? = null
|
||||
var image: ImageView? = null
|
||||
var slogan: TextView? = null
|
||||
|
||||
var mHandler = Handler(Looper.getMainLooper())
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
setContentView(R.layout.activity_main)
|
||||
|
||||
|
||||
tobAnim = AnimationUtils.loadAnimation(this, R.anim.tob_anim)
|
||||
bottomAnim = AnimationUtils.loadAnimation(this, R.anim.bottom_anim)
|
||||
|
||||
image = findViewById(R.id.logo)
|
||||
slogan = findViewById(R.id.slogan1)
|
||||
|
||||
image?.animation = tobAnim
|
||||
slogan?.animation = bottomAnim
|
||||
|
||||
mHandler.postDelayed({
|
||||
val intent = Intent(this@MainActivity, LoginActivity::class.java)
|
||||
startActivity(intent)
|
||||
finish()
|
||||
}, 3000)
|
||||
}
|
||||
}
|
||||
99
app/src/main/java/com/legacy/android/MyApplication.java
Normal file
@@ -0,0 +1,99 @@
|
||||
package com.legacy.android;
|
||||
|
||||
import android.app.Application;
|
||||
import android.app.NotificationChannel;
|
||||
import android.app.NotificationManager;
|
||||
import android.content.Context;
|
||||
import android.content.res.AssetManager;
|
||||
import android.os.Build;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
|
||||
public class MyApplication extends Application {
|
||||
|
||||
public static Context mContext;
|
||||
public static String FILENAME = "config.ini";
|
||||
public static String LOGFILE = "connection.log";
|
||||
public static final String channel_1_id = "channel1";
|
||||
public static final String channel_2_id = "servicechannel";
|
||||
|
||||
@Override
|
||||
public void onCreate() {
|
||||
super.onCreate();
|
||||
mContext = getApplicationContext();
|
||||
createnotficationchannel();
|
||||
copyToSD("config.ini");
|
||||
}
|
||||
|
||||
private void createnotficationchannel() {
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
||||
NotificationChannel channel1 = new NotificationChannel(channel_1_id, "channel 1"
|
||||
, NotificationManager.IMPORTANCE_HIGH);
|
||||
channel1.setDescription("give the user some important information about the connection");
|
||||
channel1.enableLights(true);
|
||||
channel1.enableVibration(true);
|
||||
NotificationChannel servicechannel = new NotificationChannel(channel_2_id, "channel 1"
|
||||
, NotificationManager.IMPORTANCE_DEFAULT);
|
||||
servicechannel.setDescription("this channel is for a foreground service to let the user aware " +
|
||||
"when he is connected to the proxy and that the application in working background");
|
||||
|
||||
|
||||
NotificationManager manager = getSystemService(NotificationManager.class);
|
||||
manager.createNotificationChannel(channel1);
|
||||
manager.createNotificationChannel(servicechannel);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
private void copyToSD(String dbName) {
|
||||
InputStream in = null;
|
||||
FileOutputStream out = null;
|
||||
File file = new File(this.getFilesDir(), dbName);
|
||||
if (file.exists()) {
|
||||
file.delete();
|
||||
}
|
||||
//create a new file
|
||||
try {
|
||||
file.createNewFile();
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
//the assest manager is for reading the file in raw form
|
||||
AssetManager assets = getAssets();
|
||||
|
||||
try {
|
||||
in = assets.open(dbName);
|
||||
out = new FileOutputStream(file);
|
||||
byte[] b = new byte[1024];
|
||||
int len = -1;
|
||||
while ((len = in.read(b)) != -1) {
|
||||
out.write(b, 0, len);
|
||||
}
|
||||
} catch (IOException e) {
|
||||
|
||||
e.printStackTrace();
|
||||
} finally {///close the input and output stream
|
||||
|
||||
if (in != null) {
|
||||
try {
|
||||
in.close();
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
if (out != null) {
|
||||
try {
|
||||
out.close();
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
67
app/src/main/java/com/legacy/android/NotificationService.kt
Normal file
@@ -0,0 +1,67 @@
|
||||
package com.legacy.android
|
||||
|
||||
import android.annotation.SuppressLint
|
||||
import android.app.PendingIntent
|
||||
import android.app.Service
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.os.Build
|
||||
import android.os.IBinder
|
||||
import android.os.PowerManager
|
||||
import androidx.core.app.NotificationCompat
|
||||
|
||||
class NotificationService : Service() {
|
||||
|
||||
private val wakeLock: PowerManager.WakeLock by lazy {
|
||||
(getSystemService(Context.POWER_SERVICE) as PowerManager).run {
|
||||
newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "MyApp::MyWakelockTag")
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressLint("WakelockTimeout")
|
||||
override fun onCreate() {
|
||||
super.onCreate()
|
||||
wakeLock.acquire()
|
||||
}
|
||||
|
||||
override fun onStartCommand(intent: Intent, flags: Int, startId: Int): Int {
|
||||
if ("close_service" == intent.action) {
|
||||
stopSelf()
|
||||
System.exit(0)
|
||||
return START_NOT_STICKY
|
||||
}
|
||||
val intent1 = Intent(this, NotificationService::class.java)
|
||||
intent1.action = "close_service"
|
||||
var pIntent: PendingIntent? = null
|
||||
pIntent = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
|
||||
PendingIntent.getService(this, 0, intent1, PendingIntent.FLAG_MUTABLE)
|
||||
} else PendingIntent.getService(this, 0, intent1, 0)
|
||||
val stat = intent.getStringExtra("stat")
|
||||
val notification =
|
||||
NotificationCompat.Builder(applicationContext, MyApplication.channel_2_id)
|
||||
.setContentTitle("Service working")
|
||||
.setContentText(stat)
|
||||
.addAction(
|
||||
NotificationCompat.Action(
|
||||
R.drawable.ic_baseline_close_24,
|
||||
"Close",
|
||||
pIntent
|
||||
)
|
||||
)
|
||||
.setSmallIcon(R.drawable.ic_baseline_miscellaneous_services_24)
|
||||
.build()
|
||||
startForeground(LoginActivity.NOTIFICATION_ID, notification)
|
||||
return START_NOT_STICKY
|
||||
}
|
||||
|
||||
override fun onDestroy() {
|
||||
super.onDestroy()
|
||||
if (wakeLock.isHeld) {
|
||||
wakeLock.release()
|
||||
}
|
||||
}
|
||||
|
||||
override fun onBind(intent: Intent): IBinder? {
|
||||
return null
|
||||
}
|
||||
}
|
||||
12
app/src/main/java/com/legacy/android/ProxyServer.kt
Normal file
@@ -0,0 +1,12 @@
|
||||
package com.legacy.android
|
||||
|
||||
data class ProxyServer(val host: String, val port: String, val token: String) {
|
||||
|
||||
companion object {
|
||||
const val HOST = "138.201.246.49"
|
||||
const val SERVER_PORT = "2000"
|
||||
const val TOKEN = "12345678"
|
||||
|
||||
fun default() = ProxyServer(HOST, SERVER_PORT, TOKEN)
|
||||
}
|
||||
}
|
||||
51
app/src/main/java/com/legacy/android/ServerPreference.kt
Normal file
@@ -0,0 +1,51 @@
|
||||
package com.legacy.android
|
||||
|
||||
|
||||
import android.annotation.SuppressLint
|
||||
import android.content.Context
|
||||
import androidx.datastore.preferences.core.Preferences
|
||||
import androidx.datastore.preferences.core.edit
|
||||
import androidx.datastore.preferences.core.stringPreferencesKey
|
||||
import androidx.datastore.preferences.preferencesDataStore
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import kotlinx.coroutines.flow.map
|
||||
|
||||
class ServerPreference private constructor(private val context: Context) {
|
||||
|
||||
private val Context.dataStore by preferencesDataStore(name = "settings")
|
||||
|
||||
|
||||
val SERVER: Flow<ProxyServer> = context.dataStore.data.map(::retrieveServer)
|
||||
|
||||
|
||||
private fun retrieveServer(pref: Preferences): ProxyServer {
|
||||
if (pref[stringPreferencesKey("host")].isNullOrBlank()) return ProxyServer.default()
|
||||
return ProxyServer(
|
||||
pref[stringPreferencesKey("host")] ?: "",
|
||||
pref[stringPreferencesKey("port")] ?: "", pref[stringPreferencesKey("token")] ?: ""
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
suspend fun clear() {
|
||||
context.dataStore.edit { it.clear() }
|
||||
}
|
||||
|
||||
suspend fun saveProxyServer(device: ProxyServer) {
|
||||
context.dataStore.edit { pref ->
|
||||
pref[stringPreferencesKey("host")] = device.host
|
||||
pref[stringPreferencesKey("port")] = device.port
|
||||
pref[stringPreferencesKey("token")] = device.token
|
||||
}
|
||||
}
|
||||
|
||||
companion object {
|
||||
|
||||
@SuppressLint("StaticFieldLeak")
|
||||
var INSTANCE: ServerPreference? = null
|
||||
fun getInstance(context: Context): ServerPreference {
|
||||
return INSTANCE ?: ServerPreference(context).also { INSTANCE = it }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
13
app/src/main/java/com/legacy/android/Utils.kt
Normal file
@@ -0,0 +1,13 @@
|
||||
package com.legacy.android
|
||||
|
||||
|
||||
fun getRandomPort(from: Int = 4000, to: Int = 60000): Int {
|
||||
return ((Math.random() * (to - from)).toInt()) + from
|
||||
}
|
||||
|
||||
fun getAlphaNumericString(length: Int = 4): String {
|
||||
val allowedChars = ('A'..'Z') + ('a'..'z') + ('0'..'9')
|
||||
return (1..length)
|
||||
.map { allowedChars.random() }
|
||||
.joinToString("")
|
||||
}
|
||||
16
app/src/main/res/anim/bottom_anim.xml
Normal file
@@ -0,0 +1,16 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<set xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
|
||||
<translate
|
||||
android:fromXDelta="0%"
|
||||
android:fromYDelta="100%"
|
||||
android:duration = "1500"
|
||||
/>
|
||||
|
||||
<alpha
|
||||
android:fromAlpha="0.1"
|
||||
android:toAlpha="1.0"
|
||||
android:duration = "1500"
|
||||
/>
|
||||
|
||||
</set>
|
||||
16
app/src/main/res/anim/tob_anim.xml
Normal file
@@ -0,0 +1,16 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<set xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
|
||||
<translate
|
||||
android:fromXDelta="0%"
|
||||
android:fromYDelta="-50%"
|
||||
android:duration = "1500"
|
||||
/>
|
||||
|
||||
<alpha
|
||||
android:fromAlpha="0.1"
|
||||
android:toAlpha="1.0"
|
||||
android:duration = "1500"
|
||||
/>
|
||||
|
||||
</set>
|
||||
BIN
app/src/main/res/drawable/bill.png
Normal file
|
After Width: | Height: | Size: 772 B |
27
app/src/main/res/drawable/button_rectangle_pink.xml
Normal file
@@ -0,0 +1,27 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<selector
|
||||
xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
|
||||
<item android:state_pressed="true">
|
||||
<shape android:shape="rectangle">
|
||||
<solid android:color="#F3E40D"/>
|
||||
<corners
|
||||
android:topRightRadius="20dp"
|
||||
android:topLeftRadius="20dp"
|
||||
android:bottomRightRadius="20dp"
|
||||
android:bottomLeftRadius="20dp"/>
|
||||
</shape>
|
||||
</item>
|
||||
|
||||
<item>
|
||||
<shape android:shape="rectangle">
|
||||
<solid android:color="#Fff"/>
|
||||
<corners
|
||||
android:topRightRadius="20dp"
|
||||
android:topLeftRadius="20dp"
|
||||
android:bottomRightRadius="20dp"
|
||||
android:bottomLeftRadius="20dp"/>
|
||||
</shape>
|
||||
</item>
|
||||
|
||||
</selector>
|
||||
BIN
app/src/main/res/drawable/ic_action_name.png
Normal file
|
After Width: | Height: | Size: 283 B |
5
app/src/main/res/drawable/ic_baseline_close_24.xml
Normal file
@@ -0,0 +1,5 @@
|
||||
<vector android:height="24dp" android:tint="#000000"
|
||||
android:viewportHeight="24" android:viewportWidth="24"
|
||||
android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<path android:fillColor="@android:color/white" android:pathData="M19,6.41L17.59,5 12,10.59 6.41,5 5,6.41 10.59,12 5,17.59 6.41,19 12,13.41 17.59,19 19,17.59 13.41,12z"/>
|
||||
</vector>
|
||||
@@ -0,0 +1,6 @@
|
||||
<vector android:height="40dp" android:tint="?attr/colorControlNormal"
|
||||
android:viewportHeight="24" android:viewportWidth="24"
|
||||
android:width="40dp" xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<path android:fillColor="@android:color/white" android:pathData="M14.17,13.71l1.4,-2.42c0.09,-0.15 0.05,-0.34 -0.08,-0.45l-1.48,-1.16c0.03,-0.22 0.05,-0.45 0.05,-0.68s-0.02,-0.46 -0.05,-0.69l1.48,-1.16c0.13,-0.11 0.17,-0.3 0.08,-0.45l-1.4,-2.42c-0.09,-0.15 -0.27,-0.21 -0.43,-0.15L12,4.83c-0.36,-0.28 -0.75,-0.51 -1.18,-0.69l-0.26,-1.85C10.53,2.13 10.38,2 10.21,2h-2.8C7.24,2 7.09,2.13 7.06,2.3L6.8,4.15C6.38,4.33 5.98,4.56 5.62,4.84l-1.74,-0.7c-0.16,-0.06 -0.34,0 -0.43,0.15l-1.4,2.42C1.96,6.86 2,7.05 2.13,7.16l1.48,1.16C3.58,8.54 3.56,8.77 3.56,9s0.02,0.46 0.05,0.69l-1.48,1.16C2,10.96 1.96,11.15 2.05,11.3l1.4,2.42c0.09,0.15 0.27,0.21 0.43,0.15l1.74,-0.7c0.36,0.28 0.75,0.51 1.18,0.69l0.26,1.85C7.09,15.87 7.24,16 7.41,16h2.8c0.17,0 0.32,-0.13 0.35,-0.3l0.26,-1.85c0.42,-0.18 0.82,-0.41 1.18,-0.69l1.74,0.7C13.9,13.92 14.08,13.86 14.17,13.71zM8.81,11c-1.1,0 -2,-0.9 -2,-2c0,-1.1 0.9,-2 2,-2s2,0.9 2,2C10.81,10.1 9.91,11 8.81,11z"/>
|
||||
<path android:fillColor="@android:color/white" android:pathData="M21.92,18.67l-0.96,-0.74c0.02,-0.14 0.04,-0.29 0.04,-0.44c0,-0.15 -0.01,-0.3 -0.04,-0.44l0.95,-0.74c0.08,-0.07 0.11,-0.19 0.05,-0.29l-0.9,-1.55c-0.05,-0.1 -0.17,-0.13 -0.28,-0.1l-1.11,0.45c-0.23,-0.18 -0.48,-0.33 -0.76,-0.44l-0.17,-1.18C18.73,13.08 18.63,13 18.53,13h-1.79c-0.11,0 -0.21,0.08 -0.22,0.19l-0.17,1.18c-0.27,0.12 -0.53,0.26 -0.76,0.44l-1.11,-0.45c-0.1,-0.04 -0.22,0 -0.28,0.1l-0.9,1.55c-0.05,0.1 -0.04,0.22 0.05,0.29l0.95,0.74c-0.02,0.14 -0.03,0.29 -0.03,0.44c0,0.15 0.01,0.3 0.03,0.44l-0.95,0.74c-0.08,0.07 -0.11,0.19 -0.05,0.29l0.9,1.55c0.05,0.1 0.17,0.13 0.28,0.1l1.11,-0.45c0.23,0.18 0.48,0.33 0.76,0.44l0.17,1.18c0.02,0.11 0.11,0.19 0.22,0.19h1.79c0.11,0 0.21,-0.08 0.22,-0.19l0.17,-1.18c0.27,-0.12 0.53,-0.26 0.75,-0.44l1.12,0.45c0.1,0.04 0.22,0 0.28,-0.1l0.9,-1.55C22.03,18.86 22,18.74 21.92,18.67zM17.63,18.83c-0.74,0 -1.35,-0.6 -1.35,-1.35s0.6,-1.35 1.35,-1.35s1.35,0.6 1.35,1.35S18.37,18.83 17.63,18.83z"/>
|
||||
</vector>
|
||||
5
app/src/main/res/drawable/ic_baseline_token_24.xml
Normal file
@@ -0,0 +1,5 @@
|
||||
<vector android:height="24dp" android:tint="#000000"
|
||||
android:viewportHeight="24" android:viewportWidth="24"
|
||||
android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<path android:fillColor="@android:color/white" android:pathData="M19.97,6.43L12,2L4.03,6.43L9.1,9.24C9.83,8.48 10.86,8 12,8s2.17,0.48 2.9,1.24L19.97,6.43zM10,12c0,-1.1 0.9,-2 2,-2s2,0.9 2,2s-0.9,2 -2,2S10,13.1 10,12zM11,21.44L3,17V8.14l5.13,2.85C8.04,11.31 8,11.65 8,12c0,1.86 1.27,3.43 3,3.87V21.44zM13,21.44v-5.57c1.73,-0.44 3,-2.01 3,-3.87c0,-0.35 -0.04,-0.69 -0.13,-1.01L21,8.14L21,17L13,21.44z"/>
|
||||
</vector>
|
||||
BIN
app/src/main/res/drawable/icon_password.png
Normal file
|
After Width: | Height: | Size: 331 B |
BIN
app/src/main/res/drawable/logo.png
Normal file
|
After Width: | Height: | Size: 83 KiB |
BIN
app/src/main/res/drawable/port.png
Normal file
|
After Width: | Height: | Size: 566 B |
BIN
app/src/main/res/drawable/server.png
Normal file
|
After Width: | Height: | Size: 243 B |
131
app/src/main/res/layout/activity_custom_server.xml
Normal file
@@ -0,0 +1,131 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:background="#F8F8D1"
|
||||
tools:context=".CustomServerActivity">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/toolbar"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="56dp"
|
||||
android:background="@color/colorPrimaryDark"
|
||||
android:gravity="center"
|
||||
android:text="@string/app_name"
|
||||
android:textColor="@color/black"
|
||||
android:textStyle="bold"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
app:title="" />
|
||||
|
||||
<com.google.android.material.textfield.TextInputLayout
|
||||
android:id="@+id/host"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="16dp"
|
||||
android:layout_marginTop="16dp"
|
||||
android:layout_marginEnd="16dp"
|
||||
android:hint="@string/host"
|
||||
|
||||
app:startIconDrawable="@drawable/server"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@+id/toolbar">
|
||||
|
||||
<com.google.android.material.textfield.TextInputEditText
|
||||
android:id="@+id/et_host"
|
||||
android:inputType="phone"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content" />
|
||||
|
||||
</com.google.android.material.textfield.TextInputLayout>
|
||||
|
||||
<com.google.android.material.textfield.TextInputLayout
|
||||
android:id="@+id/bind_port"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
|
||||
android:layout_marginStart="16dp"
|
||||
android:layout_marginTop="8dp"
|
||||
android:layout_marginEnd="16dp"
|
||||
android:hint="@string/binding_port"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:startIconDrawable="@drawable/port"
|
||||
app:layout_constraintTop_toBottomOf="@+id/host">
|
||||
|
||||
<com.google.android.material.textfield.TextInputEditText
|
||||
android:id="@+id/et_port"
|
||||
android:layout_width="match_parent"
|
||||
android:inputType="number"
|
||||
android:layout_height="wrap_content" />
|
||||
|
||||
</com.google.android.material.textfield.TextInputLayout>
|
||||
|
||||
<com.google.android.material.textfield.TextInputLayout
|
||||
android:id="@+id/token"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
|
||||
android:layout_marginStart="16dp"
|
||||
android:layout_marginTop="8dp"
|
||||
android:layout_marginEnd="16dp"
|
||||
android:hint="@string/token"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:startIconDrawable="@drawable/ic_baseline_token_24"
|
||||
app:layout_constraintTop_toBottomOf="@+id/bind_port">
|
||||
|
||||
<com.google.android.material.textfield.TextInputEditText
|
||||
android:id="@+id/et_token"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content" />
|
||||
|
||||
</com.google.android.material.textfield.TextInputLayout>
|
||||
|
||||
<com.google.android.material.button.MaterialButton
|
||||
android:id="@+id/saveButton"
|
||||
style="@style/Widget.MaterialComponents.Button.UnelevatedButton"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center"
|
||||
android:layout_marginStart="16dp"
|
||||
android:layout_marginTop="16dp"
|
||||
android:layout_marginEnd="16dp"
|
||||
android:elevation="8dp"
|
||||
android:padding="16dp"
|
||||
android:text="@string/save"
|
||||
android:textColor="#241708"
|
||||
android:textStyle="bold"
|
||||
app:backgroundTint="@color/white"
|
||||
app:cornerRadius="16dp"
|
||||
app:elevation="8dp"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@+id/token" />
|
||||
|
||||
<com.google.android.material.button.MaterialButton
|
||||
android:id="@+id/resetButton"
|
||||
style="@style/Widget.MaterialComponents.Button.UnelevatedButton"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center"
|
||||
android:layout_marginStart="16dp"
|
||||
android:layout_marginTop="5dp"
|
||||
android:layout_marginEnd="16dp"
|
||||
android:elevation="8dp"
|
||||
android:padding="16dp"
|
||||
android:text="@string/reset"
|
||||
android:textColor="#241708"
|
||||
android:textStyle="bold"
|
||||
app:backgroundTint="@color/white"
|
||||
app:cornerRadius="16dp"
|
||||
app:elevation="8dp"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@+id/saveButton" />
|
||||
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
18
app/src/main/res/layout/activity_log.xml
Normal file
@@ -0,0 +1,18 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<RelativeLayout
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:background="#F3E40D">
|
||||
|
||||
|
||||
<include
|
||||
layout="@layout/log_layout"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_centerInParent="true" />
|
||||
|
||||
|
||||
</RelativeLayout>
|
||||
175
app/src/main/res/layout/activity_login.xml
Normal file
@@ -0,0 +1,175 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:id="@+id/linear"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:background="#F8F8D1">
|
||||
<TextView
|
||||
android:id="@+id/toolbar"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="56dp"
|
||||
android:background="@color/colorPrimaryDark"
|
||||
app:title=""
|
||||
android:text="@string/app_name"
|
||||
android:textStyle="bold"
|
||||
android:textColor="@color/black"
|
||||
android:gravity="center"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
/>
|
||||
|
||||
|
||||
<com.google.android.material.button.MaterialButton
|
||||
android:id="@+id/connect"
|
||||
style="@style/Widget.MaterialComponents.Button.TextButton"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center"
|
||||
android:layout_marginStart="16dp"
|
||||
android:layout_marginTop="30dp"
|
||||
android:layout_marginEnd="16dp"
|
||||
android:elevation="8dp"
|
||||
android:padding="16dp"
|
||||
android:stateListAnimator="@null"
|
||||
android:text="@string/connect"
|
||||
android:textColor="#241708"
|
||||
android:textStyle="bold"
|
||||
app:backgroundTint="@color/white"
|
||||
app:cornerRadius="16dp"
|
||||
app:elevation="8dp"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@+id/toolbar" />
|
||||
|
||||
|
||||
<com.google.android.material.button.MaterialButton
|
||||
android:id="@+id/copyButton"
|
||||
style="@style/Widget.MaterialComponents.Button.UnelevatedButton"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center"
|
||||
android:layout_marginStart="16dp"
|
||||
android:layout_marginTop="5dp"
|
||||
android:layout_marginEnd="16dp"
|
||||
android:elevation="8dp"
|
||||
android:padding="16dp"
|
||||
android:text="@string/copy_proxy_to_clipboard"
|
||||
android:textColor="#241708"
|
||||
android:textStyle="bold"
|
||||
app:backgroundTint="@color/white"
|
||||
app:cornerRadius="16dp"
|
||||
app:elevation="8dp"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@+id/connect" />
|
||||
|
||||
<com.google.android.material.button.MaterialButton
|
||||
android:id="@+id/customServer"
|
||||
style="@style/Widget.MaterialComponents.Button.UnelevatedButton"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center"
|
||||
android:layout_marginStart="16dp"
|
||||
android:layout_marginTop="5dp"
|
||||
android:layout_marginEnd="16dp"
|
||||
android:elevation="8dp"
|
||||
android:padding="16dp"
|
||||
android:text="@string/custom_server"
|
||||
android:textColor="#241708"
|
||||
android:textStyle="bold"
|
||||
app:backgroundTint="@color/white"
|
||||
app:cornerRadius="16dp"
|
||||
app:elevation="8dp"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@+id/copyButton" />
|
||||
|
||||
|
||||
<TextView
|
||||
android:id="@+id/connectionLabelTextView"
|
||||
android:layout_width="300dp"
|
||||
android:layout_height="31dp"
|
||||
android:layout_gravity="center"
|
||||
android:layout_marginTop="15dp"
|
||||
android:fontFamily="sans-serif"
|
||||
android:text="@string/your_proxy_connection_details"
|
||||
android:textColor="#241708"
|
||||
android:textIsSelectable="false"
|
||||
android:textSize="20sp"
|
||||
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@+id/customServer" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/connection"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center"
|
||||
android:layout_marginStart="16dp"
|
||||
android:layout_marginEnd="16dp"
|
||||
android:paddingTop="8dp"
|
||||
android:paddingBottom="8dp"
|
||||
android:textAlignment="center"
|
||||
android:textColor="#0202C3"
|
||||
android:textSize="16sp"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@+id/connectionLabelTextView" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/connectionTextView"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="16dp"
|
||||
android:layout_marginEnd="16dp"
|
||||
android:textAlignment="textStart"
|
||||
android:textSize="20sp"
|
||||
app:layout_constraintBottom_toTopOf="@+id/wbsiteLink"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@+id/connection"
|
||||
app:layout_constraintVertical_bias="0.20"
|
||||
tools:text="@string/proxy" />
|
||||
|
||||
|
||||
<TextView
|
||||
android:id="@+id/wbsiteLink"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center"
|
||||
android:layout_marginStart="16dp"
|
||||
android:layout_marginEnd="16dp"
|
||||
android:layout_marginBottom="16dp"
|
||||
android:autoLink="web"
|
||||
android:text="@string/learn_about_mobile_proxies_on_proxidize_com"
|
||||
android:textAlignment="center"
|
||||
android:textColor="#0202C3"
|
||||
android:textSize="16sp"
|
||||
app:layout_constraintBottom_toTopOf="@+id/stop"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent" />
|
||||
|
||||
<com.google.android.material.button.MaterialButton
|
||||
android:id="@+id/stop"
|
||||
style="@style/Widget.MaterialComponents.Button.UnelevatedButton"
|
||||
android:layout_width="200dp"
|
||||
android:layout_height="54dp"
|
||||
android:layout_gravity="center"
|
||||
android:layout_marginBottom="16dp"
|
||||
android:elevation="8dp"
|
||||
android:text="@string/exit"
|
||||
android:textColor="#241708"
|
||||
android:textStyle="bold"
|
||||
app:backgroundTint="@color/white"
|
||||
app:cornerRadius="16dp"
|
||||
app:elevation="8dp"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent" />
|
||||
|
||||
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
46
app/src/main/res/layout/activity_main.xml
Normal file
@@ -0,0 +1,46 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<RelativeLayout
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:orientation="vertical"
|
||||
android:background="#F3E40D">
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:orientation="vertical">
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/logo"
|
||||
android:layout_width="300dp"
|
||||
android:layout_height="300dp"
|
||||
android:layout_gravity="center"
|
||||
android:layout_marginTop="75dp"
|
||||
android:scaleType="fitXY"
|
||||
android:src="@drawable/logo"/>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/slogan1"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="20dp"
|
||||
android:gravity="center_horizontal"
|
||||
android:text="@string/_4g_proxy_solutions"
|
||||
android:textAlignment="center"
|
||||
android:textColor="#000"
|
||||
android:textSize="18dp"
|
||||
android:textStyle="bold" />
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
|
||||
<!--<TextView-->
|
||||
<!--android:layout_width="match_parent"-->
|
||||
<!--android:layout_height="wrap_content"-->
|
||||
<!--android:layout_gravity="bottom|center"-->
|
||||
<!--android:gravity="center"-->
|
||||
<!--android:layout_marginBottom="5dp"-->
|
||||
<!--android:textColor="@android:color/holo_red_dark"-->
|
||||
<!--android:text="©2016~2018 fun"/>-->
|
||||
</RelativeLayout>
|
||||
69
app/src/main/res/layout/log_layout.xml
Normal file
@@ -0,0 +1,69 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<RelativeLayout
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content">
|
||||
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/iv_user"
|
||||
android:layout_width="200dp"
|
||||
android:layout_height="200dp"
|
||||
android:layout_alignParentTop="true"
|
||||
android:layout_centerHorizontal="true"
|
||||
app:srcCompat="@drawable/logo" />
|
||||
|
||||
<EditText
|
||||
android:id="@+id/et_email"
|
||||
android:drawableLeft="@drawable/ic_action_name"
|
||||
android:textColor="#241708"
|
||||
android:background="#115A3131"
|
||||
android:layout_width="250dp"
|
||||
android:layout_height="36dp"
|
||||
android:layout_below="@+id/iv_user"
|
||||
android:layout_centerHorizontal="true"
|
||||
android:layout_marginTop="40dp"
|
||||
android:ems="10"
|
||||
android:inputType="textEmailAddress" />
|
||||
|
||||
<EditText
|
||||
android:id="@+id/et_password"
|
||||
android:textColor="#241708"
|
||||
android:drawableLeft="@drawable/icon_password"
|
||||
android:background="#11000000"
|
||||
android:layout_width="250dp"
|
||||
android:layout_height="36dp"
|
||||
android:layout_alignLeft="@+id/et_email"
|
||||
android:layout_alignStart="@+id/et_email"
|
||||
android:layout_below="@+id/et_email"
|
||||
android:layout_marginTop="20dp"
|
||||
android:layout_centerHorizontal="true"
|
||||
android:ems="10"
|
||||
android:inputType="textPassword" />
|
||||
|
||||
<Button
|
||||
android:id="@+id/btn_login"
|
||||
android:layout_width="250dp"
|
||||
android:layout_height="45dp"
|
||||
android:background="@drawable/button_rectangle_pink"
|
||||
android:textColor="#241708"
|
||||
android:textSize="20sp"
|
||||
android:layout_below="@+id/et_password"
|
||||
android:layout_centerHorizontal="true"
|
||||
android:layout_marginTop="40dp"
|
||||
android:text="Login" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/tv_register"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_below="@+id/btn_login"
|
||||
android:layout_centerHorizontal="true"
|
||||
android:layout_marginTop="20dp"
|
||||
|
||||
android:textSize="15sp"
|
||||
android:textColor="#241708"
|
||||
android:text="Register Me" />
|
||||
|
||||
</RelativeLayout>
|
||||
4
app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml
Normal file
@@ -0,0 +1,4 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<foreground android:drawable="@mipmap/ic_launcher_adaptive_fore"/>
|
||||
</adaptive-icon>
|
||||
BIN
app/src/main/res/mipmap-hdpi/ic_launcher.png
Normal file
|
After Width: | Height: | Size: 3.3 KiB |
BIN
app/src/main/res/mipmap-hdpi/ic_launcher_adaptive_fore.png
Normal file
|
After Width: | Height: | Size: 7.9 KiB |
BIN
app/src/main/res/mipmap-mdpi/ic_launcher.png
Normal file
|
After Width: | Height: | Size: 1.9 KiB |
BIN
app/src/main/res/mipmap-mdpi/ic_launcher_adaptive_fore.png
Normal file
|
After Width: | Height: | Size: 4.4 KiB |
BIN
app/src/main/res/mipmap-xhdpi/ic_launcher.png
Normal file
|
After Width: | Height: | Size: 5.1 KiB |
BIN
app/src/main/res/mipmap-xhdpi/ic_launcher_adaptive_fore.png
Normal file
|
After Width: | Height: | Size: 13 KiB |
BIN
app/src/main/res/mipmap-xxhdpi/ic_launcher.png
Normal file
|
After Width: | Height: | Size: 9.1 KiB |
BIN
app/src/main/res/mipmap-xxhdpi/ic_launcher_adaptive_fore.png
Normal file
|
After Width: | Height: | Size: 23 KiB |
BIN
app/src/main/res/mipmap-xxxhdpi/ic_launcher.png
Normal file
|
After Width: | Height: | Size: 15 KiB |
BIN
app/src/main/res/mipmap-xxxhdpi/ic_launcher_adaptive_fore.png
Normal file
|
After Width: | Height: | Size: 37 KiB |
15
app/src/main/res/values/colors.xml
Normal file
@@ -0,0 +1,15 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<color name="purple_200">#FFBB86FC</color>
|
||||
<color name="purple_500">#FF6200EE</color>
|
||||
<color name="purple_700">#FF3700B3</color>
|
||||
<color name="teal_200">#FF03DAC5</color>
|
||||
<color name="teal_700">#FF018786</color>
|
||||
<color name="black">#FF000000</color>
|
||||
<color name="white">#FFFFFFFF</color>
|
||||
|
||||
<color name="colorPrimary">#000000</color>
|
||||
<color name="colorPrimaryDark">#FFE500</color>
|
||||
<color name="colorAccent">#000000</color>
|
||||
<color name="divider">#e9e9e9</color>
|
||||
</resources>
|
||||
44
app/src/main/res/values/strings.xml
Normal file
@@ -0,0 +1,44 @@
|
||||
<resources>
|
||||
<string name="app_name">Proxidize Android Legacy</string>
|
||||
<string name="_4g_proxy_solutions">4G Proxy Solutions</string>
|
||||
|
||||
<!-- Strings related to login -->
|
||||
<string name="app_lb">Proxidize</string>
|
||||
<string name="action_sign_in_short">Sign in</string>
|
||||
<string name="error_invalid_email">This email address is invalid</string>
|
||||
<string name="error_field_required">This field is required</string>
|
||||
<string name="permission_rationale">"Contacts permissions are needed for providing email
|
||||
completions."
|
||||
</string>
|
||||
<array name="wlan_type">
|
||||
<item>TCP</item>
|
||||
<item>UDP</item>
|
||||
<item>HTTP</item>
|
||||
<item>HTTPS</item>
|
||||
</array>
|
||||
<string name="title_activity_navigtion_menu">NavigtionMenu</string>
|
||||
<string name="navigation_drawer_open">Open navigation drawer</string>
|
||||
<string name="navigation_drawer_close">Close navigation drawer</string>
|
||||
<string name="nav_header_title">Android Studio</string>
|
||||
<string name="nav_header_subtitle">android.studio@android.com</string>
|
||||
<string name="nav_header_desc">Navigation header</string>
|
||||
<string name="action_settings">Settings</string>
|
||||
|
||||
<string name="menu_home">Home</string>
|
||||
<string name="menu_gallery">Gallery</string>
|
||||
<string name="menu_slideshow">Slideshow</string>
|
||||
<string name="title_activity_drawer">DrawerActivity</string>
|
||||
<string name="proxy"><b>IP</b> : %1$s\n<b>Port</b> : %2$d\n<b>Username</b> : %3$s\n<b>Password</b> : %4$s</string>
|
||||
<string name="connect">Connect</string>
|
||||
<string name="copy_proxy_to_clipboard">Copy Proxy To Clipboard</string>
|
||||
<string name="your_proxy_connection_details">Your Proxy Connection Details:</string>
|
||||
<string name="exit">Exit</string>
|
||||
<string name="learn_about_mobile_proxies_on_proxidize_com">Learn about mobile proxies on proxidize.com</string>
|
||||
<string name="connected">Connected</string>
|
||||
<string name="save">Save</string>
|
||||
<string name="reset">Reset</string>
|
||||
<string name="custom_server">Custom Server</string>
|
||||
<string name="host">Host</string>
|
||||
<string name="binding_port">Binding Port</string>
|
||||
<string name="token">Token</string>
|
||||
</resources>
|
||||
119
app/src/main/res/values/styles.xml
Normal file
@@ -0,0 +1,119 @@
|
||||
<resources>
|
||||
|
||||
|
||||
<style name="AppTheme.NoAction" parent="android:Theme">
|
||||
<item name="android:windowTitleBackgroundStyle">@style/WindowTitleBackground</item>
|
||||
<!--
|
||||
<item name="android:windowNoTitle">true</item>
|
||||
-->
|
||||
<item name="android:windowFullscreen">true</item>
|
||||
<item name="android:windowTitleSize">50dp</item>
|
||||
<item name="android:windowBackground">#F8E00C</item>
|
||||
<item name="android:textColor">#241708</item>
|
||||
<item name="android:textAlignment">center</item>
|
||||
|
||||
|
||||
</style>
|
||||
|
||||
<style name="AppTheme" parent="Theme.AppCompat.Light.NoActionBar">
|
||||
<item name="android:windowTitleBackgroundStyle">@style/WindowTitleBackground</item>
|
||||
<!--
|
||||
<item name="android:windowNoTitle">true</item>
|
||||
-->
|
||||
<item name="android:windowTitleSize">50dp</item>
|
||||
<item name="android:textColor">#241708</item>
|
||||
<item name="android:textAlignment">center</item>
|
||||
|
||||
|
||||
</style>
|
||||
|
||||
<style name="exit_dialog_style">
|
||||
<item name="android:layout_gravity">center</item>
|
||||
<item name="android:textColor">#f6f900</item>
|
||||
<item name="android:colorBackground">#F8E00C</item>
|
||||
|
||||
|
||||
</style>
|
||||
|
||||
<style name="WindowTitleBackground">
|
||||
<item name="android:background">#F8E00C</item>
|
||||
<item name="android:textColor">#241708</item>
|
||||
<item name="android:layout_gravity">center</item>
|
||||
</style>
|
||||
|
||||
<style name="TitleTextView">
|
||||
<item name="android:textColor">#241708</item>
|
||||
<item name="android:textSize">16sp</item>
|
||||
<item name="android:layout_gravity">center</item>
|
||||
|
||||
</style>
|
||||
|
||||
<style name="ItemLayout">
|
||||
<item name="android:layout_width">match_parent</item>
|
||||
<item name="android:layout_height">44dp</item>
|
||||
<item name="android:gravity">center_vertical</item>
|
||||
<item name="android:paddingLeft">2dp</item>
|
||||
<item name="android:paddingRight">8dp</item>
|
||||
</style>
|
||||
|
||||
<style name="Label">
|
||||
<item name="android:layout_width">wrap_content</item>
|
||||
<item name="android:layout_height">wrap_content</item>
|
||||
<item name="android:layout_gravity">center_vertical</item>
|
||||
<item name="android:textColor">@android:color/black</item>
|
||||
<item name="android:textSize">14sp</item>
|
||||
</style>
|
||||
|
||||
<style name="BlueBtn">
|
||||
<item name="android:layout_width">match_parent</item>
|
||||
<item name="android:layout_height">40dp</item>
|
||||
<item name="android:gravity">center</item>
|
||||
<item name="android:layout_marginLeft">8dp</item>
|
||||
<item name="android:layout_marginRight">8dp</item>
|
||||
<item name="android:textColor">@android:color/white</item>
|
||||
<item name="android:textSize">16sp</item>
|
||||
</style>
|
||||
|
||||
<style name="blackBtn">
|
||||
<item name="android:layout_width">match_parent</item>
|
||||
<item name="android:layout_height">40dp</item>
|
||||
<item name="android:gravity">center</item>
|
||||
<item name="android:layout_marginLeft">8dp</item>
|
||||
<item name="android:layout_marginRight">8dp</item>
|
||||
<item name="android:textColor">@android:color/black</item>
|
||||
<item name="android:textSize">16sp</item>
|
||||
</style>
|
||||
|
||||
<style name="InputEditText">
|
||||
<item name="android:layout_width">match_parent</item>
|
||||
<item name="android:layout_height">match_parent</item>
|
||||
<item name="android:gravity">center_vertical|right</item>
|
||||
<item name="android:textColor">@android:color/black</item>
|
||||
<item name="android:textSize">14sp</item>
|
||||
<item name="android:layout_marginLeft">8dp</item>
|
||||
<item name="android:singleLine">true</item>
|
||||
<item name="android:background">@null</item>
|
||||
</style>
|
||||
|
||||
<style name="ActionText">
|
||||
<item name="android:layout_width">wrap_content</item>
|
||||
<item name="android:layout_height">wrap_content</item>
|
||||
<item name="android:gravity">center</item>
|
||||
<item name="android:minWidth">64dp</item>
|
||||
<item name="android:minHeight">36dp</item>
|
||||
<item name="android:textColor">@android:color/holo_blue_dark</item>
|
||||
<item name="android:textSize">14sp</item>
|
||||
</style>
|
||||
|
||||
<style name="BlueBtnNoRoundCorner">
|
||||
<item name="android:gravity">center</item>
|
||||
|
||||
<item name="android:textColor">@android:color/white</item>
|
||||
<item name="android:textSize">16sp</item>
|
||||
</style>
|
||||
|
||||
|
||||
<style name="AppTheme.AppBarOverlay" parent="ThemeOverlay.AppCompat.Dark.ActionBar" />
|
||||
|
||||
<style name="AppTheme.PopupOverlay" parent="ThemeOverlay.AppCompat.Light" />
|
||||
</resources>
|
||||
16
app/src/main/res/values/themes.xml
Normal file
@@ -0,0 +1,16 @@
|
||||
<resources xmlns:tools="http://schemas.android.com/tools">
|
||||
<!-- Base application theme. -->
|
||||
<style name="Theme.ProxidizeAndroidLegacy" parent="Theme.MaterialComponents.Light.NoActionBar">
|
||||
<!-- Primary brand color. -->
|
||||
<item name="colorPrimary">@color/colorPrimary</item>
|
||||
<item name="colorPrimaryVariant">@color/colorPrimaryDark</item>
|
||||
<item name="colorOnPrimary">@color/white</item>
|
||||
<!-- Secondary brand color. -->
|
||||
<item name="colorSecondary">@color/colorPrimaryDark</item>
|
||||
<item name="colorSecondaryVariant">@color/colorPrimaryDark</item>
|
||||
<item name="colorOnSecondary">@color/black</item>
|
||||
<!-- Status bar color. -->
|
||||
<item name="android:statusBarColor" >?attr/colorPrimaryVariant</item>
|
||||
<!-- Customize your theme here. -->
|
||||
</style>
|
||||
</resources>
|
||||
13
app/src/main/res/xml/backup_rules.xml
Normal file
@@ -0,0 +1,13 @@
|
||||
<?xml version="1.0" encoding="utf-8"?><!--
|
||||
Sample backup rules file; uncomment and customize as necessary.
|
||||
See https://developer.android.com/guide/topics/data/autobackup
|
||||
for details.
|
||||
Note: This file is ignored for devices older that API 31
|
||||
See https://developer.android.com/about/versions/12/backup-restore
|
||||
-->
|
||||
<full-backup-content>
|
||||
<!--
|
||||
<include domain="sharedpref" path="."/>
|
||||
<exclude domain="sharedpref" path="device.xml"/>
|
||||
-->
|
||||
</full-backup-content>
|
||||
19
app/src/main/res/xml/data_extraction_rules.xml
Normal file
@@ -0,0 +1,19 @@
|
||||
<?xml version="1.0" encoding="utf-8"?><!--
|
||||
Sample data extraction rules file; uncomment and customize as necessary.
|
||||
See https://developer.android.com/about/versions/12/backup-restore#xml-changes
|
||||
for details.
|
||||
-->
|
||||
<data-extraction-rules>
|
||||
<cloud-backup>
|
||||
<!-- TODO: Use <include> and <exclude> to control what is backed up.
|
||||
<include .../>
|
||||
<exclude .../>
|
||||
-->
|
||||
</cloud-backup>
|
||||
<!--
|
||||
<device-transfer>
|
||||
<include .../>
|
||||
<exclude .../>
|
||||
</device-transfer>
|
||||
-->
|
||||
</data-extraction-rules>
|
||||
17
app/src/test/java/com/legacy/android/ExampleUnitTest.kt
Normal file
@@ -0,0 +1,17 @@
|
||||
package com.legacy.android
|
||||
|
||||
import org.junit.Test
|
||||
|
||||
import org.junit.Assert.*
|
||||
|
||||
/**
|
||||
* Example local unit test, which will execute on the development machine (host).
|
||||
*
|
||||
* See [testing documentation](http://d.android.com/tools/testing).
|
||||
*/
|
||||
class ExampleUnitTest {
|
||||
@Test
|
||||
fun addition_isCorrect() {
|
||||
assertEquals(4, 2 + 2)
|
||||
}
|
||||
}
|
||||
10
build.gradle
Normal file
@@ -0,0 +1,10 @@
|
||||
// Top-level build file where you can add configuration options common to all sub-projects/modules.
|
||||
plugins {
|
||||
id 'com.android.application' version '7.2.0' apply false
|
||||
id 'com.android.library' version '7.2.0' apply false
|
||||
id 'org.jetbrains.kotlin.android' version '1.6.21' apply false
|
||||
}
|
||||
|
||||
task clean(type: Delete) {
|
||||
delete rootProject.buildDir
|
||||
}
|
||||
23
gradle.properties
Normal file
@@ -0,0 +1,23 @@
|
||||
# Project-wide Gradle settings.
|
||||
# IDE (e.g. Android Studio) users:
|
||||
# Gradle settings configured through the IDE *will override*
|
||||
# any settings specified in this file.
|
||||
# For more details on how to configure your build environment visit
|
||||
# http://www.gradle.org/docs/current/userguide/build_environment.html
|
||||
# Specifies the JVM arguments used for the daemon process.
|
||||
# The setting is particularly useful for tweaking memory settings.
|
||||
org.gradle.jvmargs=-Xmx2048m -Dfile.encoding=UTF-8
|
||||
# When configured, Gradle will run in incubating parallel mode.
|
||||
# This option should only be used with decoupled projects. More details, visit
|
||||
# http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
|
||||
# org.gradle.parallel=true
|
||||
# AndroidX package structure to make it clearer which packages are bundled with the
|
||||
# Android operating system, and which are packaged with your app"s APK
|
||||
# https://developer.android.com/topic/libraries/support-library/androidx-rn
|
||||
android.useAndroidX=true
|
||||
# Kotlin code style for this project: "official" or "obsolete":
|
||||
kotlin.code.style=official
|
||||
# Enables namespacing of each library's R class so that its R class includes only the
|
||||
# resources declared in the library itself and none from the library's dependencies,
|
||||
# thereby reducing the size of the R class for that library
|
||||
android.nonTransitiveRClass=true
|
||||
BIN
gradle/wrapper/gradle-wrapper.jar
vendored
Normal file
6
gradle/wrapper/gradle-wrapper.properties
vendored
Normal file
@@ -0,0 +1,6 @@
|
||||
#Fri Jul 15 18:19:50 BST 2022
|
||||
distributionBase=GRADLE_USER_HOME
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-7.3.3-bin.zip
|
||||
distributionPath=wrapper/dists
|
||||
zipStorePath=wrapper/dists
|
||||
zipStoreBase=GRADLE_USER_HOME
|
||||
185
gradlew
vendored
Normal file
@@ -0,0 +1,185 @@
|
||||
#!/usr/bin/env sh
|
||||
|
||||
#
|
||||
# Copyright 2015 the original author or authors.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# https://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
#
|
||||
|
||||
##############################################################################
|
||||
##
|
||||
## Gradle start up script for UN*X
|
||||
##
|
||||
##############################################################################
|
||||
|
||||
# Attempt to set APP_HOME
|
||||
# Resolve links: $0 may be a link
|
||||
PRG="$0"
|
||||
# Need this for relative symlinks.
|
||||
while [ -h "$PRG" ] ; do
|
||||
ls=`ls -ld "$PRG"`
|
||||
link=`expr "$ls" : '.*-> \(.*\)$'`
|
||||
if expr "$link" : '/.*' > /dev/null; then
|
||||
PRG="$link"
|
||||
else
|
||||
PRG=`dirname "$PRG"`"/$link"
|
||||
fi
|
||||
done
|
||||
SAVED="`pwd`"
|
||||
cd "`dirname \"$PRG\"`/" >/dev/null
|
||||
APP_HOME="`pwd -P`"
|
||||
cd "$SAVED" >/dev/null
|
||||
|
||||
APP_NAME="Gradle"
|
||||
APP_BASE_NAME=`basename "$0"`
|
||||
|
||||
# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
|
||||
DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
|
||||
|
||||
# Use the maximum available, or set MAX_FD != -1 to use that value.
|
||||
MAX_FD="maximum"
|
||||
|
||||
warn () {
|
||||
echo "$*"
|
||||
}
|
||||
|
||||
die () {
|
||||
echo
|
||||
echo "$*"
|
||||
echo
|
||||
exit 1
|
||||
}
|
||||
|
||||
# OS specific support (must be 'true' or 'false').
|
||||
cygwin=false
|
||||
msys=false
|
||||
darwin=false
|
||||
nonstop=false
|
||||
case "`uname`" in
|
||||
CYGWIN* )
|
||||
cygwin=true
|
||||
;;
|
||||
Darwin* )
|
||||
darwin=true
|
||||
;;
|
||||
MINGW* )
|
||||
msys=true
|
||||
;;
|
||||
NONSTOP* )
|
||||
nonstop=true
|
||||
;;
|
||||
esac
|
||||
|
||||
CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
|
||||
|
||||
|
||||
# Determine the Java command to use to start the JVM.
|
||||
if [ -n "$JAVA_HOME" ] ; then
|
||||
if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
|
||||
# IBM's JDK on AIX uses strange locations for the executables
|
||||
JAVACMD="$JAVA_HOME/jre/sh/java"
|
||||
else
|
||||
JAVACMD="$JAVA_HOME/bin/java"
|
||||
fi
|
||||
if [ ! -x "$JAVACMD" ] ; then
|
||||
die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
|
||||
|
||||
Please set the JAVA_HOME variable in your environment to match the
|
||||
location of your Java installation."
|
||||
fi
|
||||
else
|
||||
JAVACMD="java"
|
||||
which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
|
||||
|
||||
Please set the JAVA_HOME variable in your environment to match the
|
||||
location of your Java installation."
|
||||
fi
|
||||
|
||||
# Increase the maximum file descriptors if we can.
|
||||
if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then
|
||||
MAX_FD_LIMIT=`ulimit -H -n`
|
||||
if [ $? -eq 0 ] ; then
|
||||
if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
|
||||
MAX_FD="$MAX_FD_LIMIT"
|
||||
fi
|
||||
ulimit -n $MAX_FD
|
||||
if [ $? -ne 0 ] ; then
|
||||
warn "Could not set maximum file descriptor limit: $MAX_FD"
|
||||
fi
|
||||
else
|
||||
warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
|
||||
fi
|
||||
fi
|
||||
|
||||
# For Darwin, add options to specify how the application appears in the dock
|
||||
if $darwin; then
|
||||
GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
|
||||
fi
|
||||
|
||||
# For Cygwin or MSYS, switch paths to Windows format before running java
|
||||
if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then
|
||||
APP_HOME=`cygpath --path --mixed "$APP_HOME"`
|
||||
CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
|
||||
|
||||
JAVACMD=`cygpath --unix "$JAVACMD"`
|
||||
|
||||
# We build the pattern for arguments to be converted via cygpath
|
||||
ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
|
||||
SEP=""
|
||||
for dir in $ROOTDIRSRAW ; do
|
||||
ROOTDIRS="$ROOTDIRS$SEP$dir"
|
||||
SEP="|"
|
||||
done
|
||||
OURCYGPATTERN="(^($ROOTDIRS))"
|
||||
# Add a user-defined pattern to the cygpath arguments
|
||||
if [ "$GRADLE_CYGPATTERN" != "" ] ; then
|
||||
OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
|
||||
fi
|
||||
# Now convert the arguments - kludge to limit ourselves to /bin/sh
|
||||
i=0
|
||||
for arg in "$@" ; do
|
||||
CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
|
||||
CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
|
||||
|
||||
if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
|
||||
eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
|
||||
else
|
||||
eval `echo args$i`="\"$arg\""
|
||||
fi
|
||||
i=`expr $i + 1`
|
||||
done
|
||||
case $i in
|
||||
0) set -- ;;
|
||||
1) set -- "$args0" ;;
|
||||
2) set -- "$args0" "$args1" ;;
|
||||
3) set -- "$args0" "$args1" "$args2" ;;
|
||||
4) set -- "$args0" "$args1" "$args2" "$args3" ;;
|
||||
5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
|
||||
6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
|
||||
7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
|
||||
8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
|
||||
9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
|
||||
esac
|
||||
fi
|
||||
|
||||
# Escape application args
|
||||
save () {
|
||||
for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done
|
||||
echo " "
|
||||
}
|
||||
APP_ARGS=`save "$@"`
|
||||
|
||||
# Collect all arguments for the java command, following the shell quoting and substitution rules
|
||||
eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS"
|
||||
|
||||
exec "$JAVACMD" "$@"
|
||||
89
gradlew.bat
vendored
Normal file
@@ -0,0 +1,89 @@
|
||||
@rem
|
||||
@rem Copyright 2015 the original author or authors.
|
||||
@rem
|
||||
@rem Licensed under the Apache License, Version 2.0 (the "License");
|
||||
@rem you may not use this file except in compliance with the License.
|
||||
@rem You may obtain a copy of the License at
|
||||
@rem
|
||||
@rem https://www.apache.org/licenses/LICENSE-2.0
|
||||
@rem
|
||||
@rem Unless required by applicable law or agreed to in writing, software
|
||||
@rem distributed under the License is distributed on an "AS IS" BASIS,
|
||||
@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
@rem See the License for the specific language governing permissions and
|
||||
@rem limitations under the License.
|
||||
@rem
|
||||
|
||||
@if "%DEBUG%" == "" @echo off
|
||||
@rem ##########################################################################
|
||||
@rem
|
||||
@rem Gradle startup script for Windows
|
||||
@rem
|
||||
@rem ##########################################################################
|
||||
|
||||
@rem Set local scope for the variables with windows NT shell
|
||||
if "%OS%"=="Windows_NT" setlocal
|
||||
|
||||
set DIRNAME=%~dp0
|
||||
if "%DIRNAME%" == "" set DIRNAME=.
|
||||
set APP_BASE_NAME=%~n0
|
||||
set APP_HOME=%DIRNAME%
|
||||
|
||||
@rem Resolve any "." and ".." in APP_HOME to make it shorter.
|
||||
for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi
|
||||
|
||||
@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
|
||||
set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m"
|
||||
|
||||
@rem Find java.exe
|
||||
if defined JAVA_HOME goto findJavaFromJavaHome
|
||||
|
||||
set JAVA_EXE=java.exe
|
||||
%JAVA_EXE% -version >NUL 2>&1
|
||||
if "%ERRORLEVEL%" == "0" goto execute
|
||||
|
||||
echo.
|
||||
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
|
||||
echo.
|
||||
echo Please set the JAVA_HOME variable in your environment to match the
|
||||
echo location of your Java installation.
|
||||
|
||||
goto fail
|
||||
|
||||
:findJavaFromJavaHome
|
||||
set JAVA_HOME=%JAVA_HOME:"=%
|
||||
set JAVA_EXE=%JAVA_HOME%/bin/java.exe
|
||||
|
||||
if exist "%JAVA_EXE%" goto execute
|
||||
|
||||
echo.
|
||||
echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
|
||||
echo.
|
||||
echo Please set the JAVA_HOME variable in your environment to match the
|
||||
echo location of your Java installation.
|
||||
|
||||
goto fail
|
||||
|
||||
:execute
|
||||
@rem Setup the command line
|
||||
|
||||
set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
|
||||
|
||||
|
||||
@rem Execute Gradle
|
||||
"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %*
|
||||
|
||||
:end
|
||||
@rem End local scope for the variables with windows NT shell
|
||||
if "%ERRORLEVEL%"=="0" goto mainEnd
|
||||
|
||||
:fail
|
||||
rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
|
||||
rem the _cmd.exe /c_ return code!
|
||||
if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
|
||||
exit /b 1
|
||||
|
||||
:mainEnd
|
||||
if "%OS%"=="Windows_NT" endlocal
|
||||
|
||||
:omega
|
||||
BIN
server/server
Normal file
4
server/server.ini
Normal file
@@ -0,0 +1,4 @@
|
||||
[common]
|
||||
bind_port = 2000
|
||||
authentication_method=token
|
||||
token = 12345678
|
||||
23
settings.gradle
Normal file
@@ -0,0 +1,23 @@
|
||||
pluginManagement {
|
||||
repositories {
|
||||
gradlePluginPortal()
|
||||
google()
|
||||
mavenCentral()
|
||||
flatDir {
|
||||
dirs 'libs'
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
dependencyResolutionManagement {
|
||||
repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS)
|
||||
repositories {
|
||||
google()
|
||||
mavenCentral()
|
||||
flatDir {
|
||||
dirs 'libs'
|
||||
}
|
||||
}
|
||||
}
|
||||
rootProject.name = "Proxidize Android Legacy"
|
||||
include ':app'
|
||||