├── .dockerignore
├── .github
└── workflows
│ └── build-apk.yml
├── .gitignore
├── .yamllint
├── Dockerfile
├── README.md
├── app
├── build.gradle
├── libs
│ └── protobuf-java-3.6.0.jar
├── proguard-rules.pro
└── src
│ ├── androidTest
│ └── java
│ │ └── uk
│ │ └── co
│ │ └── borconi
│ │ └── emil
│ │ └── aagateway
│ │ └── ExampleInstrumentedTest.java
│ ├── main
│ ├── AndroidManifest.xml
│ ├── ic_launcher-web.png
│ ├── java
│ │ └── uk
│ │ │ └── co
│ │ │ └── borconi
│ │ │ └── emil
│ │ │ └── aagateway
│ │ │ ├── HackerService.java
│ │ │ ├── MainActivity.java
│ │ │ ├── PowerConnectionReceiver.java
│ │ │ └── Preferences.java
│ ├── jniLibs
│ │ ├── armeabi
│ │ │ └── libhu_jni.so
│ │ └── x86
│ │ │ └── libhu_jni.so
│ └── res
│ │ ├── drawable-v24
│ │ └── ic_launcher_foreground.xml
│ │ ├── drawable
│ │ ├── aawifi.png
│ │ ├── hu_icon_256.png
│ │ └── ic_launcher_background.xml
│ │ ├── layout
│ │ └── activity_main.xml
│ │ ├── mipmap-anydpi-v26
│ │ ├── ic_launcher.xml
│ │ └── ic_launcher_round.xml
│ │ ├── mipmap-hdpi
│ │ ├── ic_launcher.png
│ │ ├── ic_launcher_foreground.png
│ │ └── ic_launcher_round.png
│ │ ├── mipmap-mdpi
│ │ ├── ic_launcher.png
│ │ ├── ic_launcher_foreground.png
│ │ └── ic_launcher_round.png
│ │ ├── mipmap-xhdpi
│ │ ├── ic_launcher.png
│ │ ├── ic_launcher_foreground.png
│ │ └── ic_launcher_round.png
│ │ ├── mipmap-xxhdpi
│ │ ├── ic_launcher.png
│ │ ├── ic_launcher_foreground.png
│ │ └── ic_launcher_round.png
│ │ ├── mipmap-xxxhdpi
│ │ ├── ic_launcher.png
│ │ ├── ic_launcher_foreground.png
│ │ └── ic_launcher_round.png
│ │ ├── values
│ │ ├── colors.xml
│ │ ├── strings.xml
│ │ ├── styles.xml
│ │ └── white.xml
│ │ └── xml
│ │ └── accessory_filter.xml
│ └── test
│ └── java
│ └── uk
│ └── co
│ └── borconi
│ └── emil
│ └── aagateway
│ └── ExampleUnitTest.java
├── build.gradle
├── build_in_docker.sh
├── gradle
└── wrapper
│ ├── gradle-wrapper.jar
│ └── gradle-wrapper.properties
├── gradlew
├── gradlew.bat
└── settings.gradle
/.dockerignore:
--------------------------------------------------------------------------------
1 | .git
2 | app/build
3 | build
4 |
--------------------------------------------------------------------------------
/.github/workflows/build-apk.yml:
--------------------------------------------------------------------------------
1 | ---
2 | name: Build APK
3 |
4 | on:
5 | push:
6 | branches:
7 | - master
8 | tags:
9 | - v*
10 | pull_request:
11 | branches:
12 | - master
13 |
14 | jobs:
15 | tests:
16 | runs-on: ubuntu-latest
17 | steps:
18 | - uses: actions/checkout@v2
19 | - name: "YamlLint"
20 | run: |
21 | docker run \
22 | --rm \
23 | -w /repo \
24 | -v $(pwd):/repo \
25 | -t \
26 | alpine:3.13 /bin/sh -c " \
27 | apk add --no-cache py-pip python3 bash \
28 | && pip3 install yamllint \
29 | && yamllint -s . \
30 | "
31 | - name: "ShellCheck"
32 | run: |
33 | docker run \
34 | --rm \
35 | -w /repo \
36 | -v $(pwd):/repo \
37 | -t \
38 | alpine:3.13 /bin/sh -c " \
39 | apk add --no-cache shellcheck bash \
40 | && shellcheck $(find . -type f -name "*.sh" | tr '\n' ' ')
41 | "
42 | build:
43 | runs-on: ubuntu-latest
44 | steps:
45 | - uses: actions/checkout@v2
46 | - name: "Build APK"
47 | run: ./build_in_docker.sh
48 | - name: Release
49 | uses: softprops/action-gh-release@v1
50 | if: startsWith(github.ref, 'refs/tags/')
51 | with:
52 | tag_name: ${{ github.ref }}
53 | name: Release ${{ github.ref }}
54 | draft: true
55 | files: |
56 | ./app/build/outputs/apk/debug/*
57 | env:
58 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} # You don't need to add this in secrets it's by default.
59 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # IDE
2 | *.iml
3 | app/*.iml
4 |
5 | # Built application files
6 | *.apk
7 | *.ap_
8 |
9 | # Files for the ART/Dalvik VM
10 | *.dex
11 |
12 | # Java class files
13 | *.class
14 |
15 | # Generated files
16 | bin/
17 | gen/
18 | out/
19 |
20 | # Gradle files
21 | .gradle/
22 | build/
23 |
24 | # Local configuration file (sdk path, etc)
25 | local.properties
26 |
27 | # Proguard folder generated by Eclipse
28 | proguard/
29 |
30 | # Log Files
31 | *.log
32 |
33 | # Android Studio Navigation editor temp files
34 | .navigation/
35 |
36 | # Android Studio captures folder
37 | captures/
38 |
39 | # IntelliJ
40 | *.iml
41 | .idea/workspace.xml
42 | .idea/tasks.xml
43 | .idea/gradle.xml
44 | .idea/assetWizardSettings.xml
45 | .idea/dictionaries
46 | .idea/libraries
47 | .idea/caches
48 |
49 | # Keystore files
50 | # Uncomment the following line if you do not want to check your keystore files in.
51 | #*.jks
52 |
53 | # External native build folder generated in Android Studio 2.2 and later
54 | .externalNativeBuild
55 |
56 | # Google Services (e.g. APIs or Firebase)
57 | google-services.json
58 |
59 | # Freeline
60 | freeline.py
61 | freeline/
62 | freeline_project_description.json
63 |
64 | # fastlane
65 | fastlane/report.xml
66 | fastlane/Preview.html
67 | fastlane/screenshots
68 | fastlane/test_output
69 | fastlane/readme.md
70 |
--------------------------------------------------------------------------------
/.yamllint:
--------------------------------------------------------------------------------
1 | ---
2 | extends: default
3 |
4 | rules:
5 | line-length: disable
6 | truthy: disable
7 |
--------------------------------------------------------------------------------
/Dockerfile:
--------------------------------------------------------------------------------
1 | FROM ubuntu:20.04
2 |
3 | ENV DEBIAN_FRONTEND=noninteractive
4 |
5 | # https://developer.android.com/studio/index.html#command-tools
6 |
7 | WORKDIR /opt/android
8 |
9 | RUN apt-get update \
10 | && apt-get install -y \
11 | curl \
12 | unzip \
13 | openjdk-8-jdk
14 |
15 | # jdk 8, 11, 13 ,16
16 | # && apt-get install -y android-sdk
17 |
18 | ENV ANDROID_HOME=/opt/android
19 | ENV PATH=$ANDROID_HOME/cmdline-tools/tools/bin/:$PATH
20 | ENV PATH=$ANDROID_HOME/emulator/:$PATH
21 | ENV PATH=$ANDROID_HOME/platform-tools/:$PATH
22 |
23 | RUN curl -L $(curl -sL https://developer.android.com/studio/index.html\#command-tools | grep "zip" | grep "linux" | grep "commandline" | grep "href" | cut -d'"' -f2) -O \
24 | && unzip $(ls | grep zip) \
25 | && rm -rf $(ls | grep zip) \
26 | && mkdir tools \
27 | && mv cmdline-tools/* tools \
28 | && mv tools cmdline-tools/ \
29 | && yes | sdkmanager --licenses
30 |
31 | # ENV GRADLE_OPTS=-Djava.io.tmpdir=/repo/
32 | # export GRADLE_OPTS=-Djava.io.tmpdir=/repo/
33 |
34 | # ./gradlew assemble
35 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # AAGateWay
2 |
3 | A modified version of [AAGateWay](https://github.com/borconi/AAGateWay) that requires [AAstarter](https://github.com/olivluca/AAstarter) on the master phone.
4 |
5 | I only tested it on my car (with a MIB 2 headuint) and my phones. The master is a Xiaomi Redmi Note 4, the slave is a Motorola Moto E 2015 (surnia), both running
6 | LineagesOs 17.1 (android 10).
7 |
8 | The MIB 2 I have is quite peculiar: when it cannot establish a connection it will briefly remove power on the usb connector and that will upset
9 | the apk released by Emil, hence the need to write this one.
10 |
11 |
12 | The steps to make it work are:
13 |
14 | 1. open the app and ensure it is using the default options _LISTENING MODE_ and _USE IPV4_.
15 | 1. setup a hotspot on the slave.
16 | 1. configure the master to connect to said hotspot and to keep using it even if it has no Internet.
17 | 1. Install this app on the slave and AAstarter on the master.
18 | 1. Start AAStarter on the master and grant it the required permissions.
19 | 1. Connect the slave to the headunit.
20 | 1. When prompted confirm that you want to use AAGateway as the default application.
21 | 1. Wait for the master to be connected to the slave's hotspot.
22 | 1. Push the button to connect to the phone on the headunit.
23 |
24 | It usually needs 2 o 3 (or more) tries before successfully establishing a connection.
25 | None of the devices needs to be rooted.
26 |
27 | The principle of operation is:
28 |
29 | * when the headunit starts it, AAGateway will send a trigger on udp port 4455 to AAstarter on the master (actually it will send it to every connected station but
30 | 1. only the master should be connected to this hotspot
31 | 1. only the master will reply
32 | * AAstarter will start Android Auto telling it to connect back to the slave.
33 | * When the slave successfully initializes the connection with both partners (the headunit and the slave) it will start moving data between them.
34 |
35 | If you set the _CONNECTING MODE_ option, then the app will work just like the original AAGateWay (it will connect to the headunit server that
36 | you'll have to manually start on the master) but with the hotspot on the slave.
37 |
38 | With the _USE IPV4_ option the app will only try ipv4 addresses to connect to the master, while with _USE IPV6_ it will only try ipv6 addresses.
39 |
40 |
41 | =========================
42 |
43 |
44 | below is the original README:
45 |
46 | # AAGateWay
47 |
48 | A super simple app which allows the connection to Android Auto over Wifi. It requires an Android Auto compatible car in the first place.
49 |
50 | # License
51 |
52 | You are free to use the code for personal use in any shape or form you want, and implement any modification you wish, however you are stictly forbiden in creating and publishing app with the same or similar purposer, regardless if the app is free or comrecial. If you wish to use the code in building and releaseing your own app, please seek written approval before proceeding.
53 |
54 | # Copyright
55 | Emil Borconi-Szedressy (C) 2017 - Wakefield - United Kingdom
56 |
57 | # Requirements
58 |
59 | * Android Studio 3.4.1 or higher
60 | * Gradle 5.1.1
61 | * Android API 27
62 |
63 |
64 | # Build
65 |
66 | ```
67 | $> ./gradlew assemble
68 | ```
69 |
70 | This will generate an `apk` file inside build directory `./app/build/outputs/apk/debug`
71 |
72 | # Install in debug device
73 |
74 | ```
75 | $> ./gradlew installDebug
76 | ```
77 |
--------------------------------------------------------------------------------
/app/build.gradle:
--------------------------------------------------------------------------------
1 | apply plugin: 'com.android.application'
2 |
3 |
4 | android {
5 | compileSdkVersion 27
6 | defaultConfig {
7 | applicationId "uk.co.borconi.emil.aagateway"
8 | minSdkVersion 14
9 | targetSdkVersion 27
10 | versionCode 1
11 | versionName "1.0.3 Alpha"
12 | testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
13 | multiDexEnabled true
14 | }
15 | buildTypes {
16 | release {
17 | minifyEnabled false
18 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
19 | }
20 | }
21 | }
22 |
23 | dependencies {
24 | implementation fileTree(include: ['*.jar'], dir: 'libs')
25 | implementation 'com.android.support:appcompat-v7:27.1.1+'
26 | implementation 'com.android.support.constraint:constraint-layout:1.0.2'
27 | testImplementation 'junit:junit:4.12'
28 | androidTestImplementation 'com.android.support.test:runner:1.0.1'
29 | androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.1'
30 | implementation files('libs/protobuf-java-3.6.0.jar')
31 |
32 | }
33 |
--------------------------------------------------------------------------------
/app/libs/protobuf-java-3.6.0.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mikeeq/aagateway/02e89d112572f0612c6c66e22e8f24a1ff7dcb01/app/libs/protobuf-java-3.6.0.jar
--------------------------------------------------------------------------------
/app/proguard-rules.pro:
--------------------------------------------------------------------------------
1 | # Add project specific ProGuard rules here.
2 | # You can control the set of applied configuration files using the
3 | # proguardFiles setting in build.gradle.
4 | #
5 | # For more details, see
6 | # http://developer.android.com/guide/developing/tools/proguard.html
7 |
8 | # If your project uses WebView with JS, uncomment the following
9 | # and specify the fully qualified class name to the JavaScript interface
10 | # class:
11 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview {
12 | # public *;
13 | #}
14 |
15 | # Uncomment this to preserve the line number information for
16 | # debugging stack traces.
17 | #-keepattributes SourceFile,LineNumberTable
18 |
19 | # If you keep the line number information, uncomment this to
20 | # hide the original source file name.
21 | #-renamesourcefileattribute SourceFile
22 |
23 |
24 |
25 |
--------------------------------------------------------------------------------
/app/src/androidTest/java/uk/co/borconi/emil/aagateway/ExampleInstrumentedTest.java:
--------------------------------------------------------------------------------
1 | package uk.co.borconi.emil.aagateway;
2 |
3 | import android.content.Context;
4 | import android.support.test.InstrumentationRegistry;
5 | import android.support.test.runner.AndroidJUnit4;
6 |
7 | import org.junit.Test;
8 | import org.junit.runner.RunWith;
9 |
10 | import static org.junit.Assert.*;
11 |
12 | /**
13 | * Instrumented test, which will execute on an Android device.
14 | *
15 | * @see Testing documentation
16 | */
17 | @RunWith(AndroidJUnit4.class)
18 | public class ExampleInstrumentedTest {
19 | @Test
20 | public void useAppContext() throws Exception {
21 | // Context of the app under test.
22 | Context appContext = InstrumentationRegistry.getTargetContext();
23 |
24 | assertEquals("uk.co.borconi.emil.aagateway", appContext.getPackageName());
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/app/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
--------------------------------------------------------------------------------
/app/src/main/ic_launcher-web.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mikeeq/aagateway/02e89d112572f0612c6c66e22e8f24a1ff7dcb01/app/src/main/ic_launcher-web.png
--------------------------------------------------------------------------------
/app/src/main/java/uk/co/borconi/emil/aagateway/HackerService.java:
--------------------------------------------------------------------------------
1 | package uk.co.borconi.emil.aagateway;
2 |
3 | import android.app.Notification;
4 | import android.app.NotificationChannel;
5 | import android.app.NotificationManager;
6 | import android.app.Service;
7 | import android.content.Context;
8 | import android.content.Intent;
9 | import android.content.SharedPreferences;
10 | import android.graphics.Color;
11 | import android.hardware.usb.UsbAccessory;
12 | import android.hardware.usb.UsbManager;
13 | import android.net.ConnectivityManager;
14 | import android.net.DhcpInfo;
15 | import android.net.wifi.WifiManager;
16 | import android.os.Binder;
17 | import android.os.Build;
18 | import android.os.IBinder;
19 | import android.os.Looper;
20 | import android.os.ParcelFileDescriptor;
21 | import android.preference.PreferenceManager;
22 | import android.util.Log;
23 |
24 | import java.io.BufferedReader;
25 | import java.io.DataInputStream;
26 | import java.io.InputStreamReader;
27 | import java.io.FileDescriptor;
28 | import java.io.FileInputStream;
29 | import java.io.FileOutputStream;
30 | import java.io.IOException;
31 | import java.io.OutputStream;
32 | import java.net.DatagramPacket;
33 | import java.net.DatagramSocket;
34 | import java.net.ServerSocket;
35 | import java.net.Socket;
36 | import java.net.InetAddress;
37 | import java.net.InetSocketAddress;
38 | import java.util.Arrays;
39 |
40 |
41 |
42 | import static android.app.NotificationManager.IMPORTANCE_HIGH;
43 |
44 |
45 |
46 | /**
47 | * Created by Emil on 25/03/2018.
48 | */
49 |
50 | public class HackerService extends Service {
51 | private static final String TAG = "AAGateWay";
52 | private NotificationManager mNotificationManager;
53 | private Intent notificationIntent;
54 | private final IBinder mBinder = new LocalBinder();
55 | private UsbAccessory mAccessory;
56 | private UsbManager mUsbManager;
57 | private ParcelFileDescriptor mFileDescriptor;
58 | private FileDescriptor fd;
59 | private FileOutputStream phoneOutputStream;
60 | private FileInputStream phoneInputStream;
61 |
62 | private static OutputStream socketoutput;
63 | private static DataInputStream socketinput;
64 | private static Socket socket;
65 | private boolean running=false;
66 | private boolean localCompleted,usbCompleted;
67 | private boolean listening;
68 | private boolean ignoreipv6;
69 | byte [] readbuffer=new byte[16384];
70 | private Thread tcpreader;
71 | private Thread usbreader;
72 |
73 | @Override
74 | public IBinder onBind(Intent intent) {
75 | return mBinder;
76 | }
77 | public class LocalBinder extends Binder {
78 | HackerService getService() {
79 | return HackerService.this;
80 | }
81 | }
82 |
83 | @Override
84 | public void onCreate() {
85 | super.onCreate();
86 |
87 | SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(getApplicationContext());
88 | listening=preferences.getBoolean(Preferences.LISTENING_MODE, true);
89 | ignoreipv6=preferences.getBoolean(Preferences.IGNORE_IPV6, true);
90 | String CHANNEL_ONE_ID = "uk.co.borconi.emil.aagateway";
91 | String CHANNEL_ONE_NAME = "Channel One";
92 | NotificationChannel notificationChannel = null;
93 | if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.O) {
94 | notificationChannel = new NotificationChannel(CHANNEL_ONE_ID,
95 | CHANNEL_ONE_NAME, IMPORTANCE_HIGH);
96 | notificationChannel.enableLights(true);
97 | notificationChannel.setLightColor(Color.RED);
98 | notificationChannel.setShowBadge(true);
99 | notificationChannel.setLockscreenVisibility(Notification.VISIBILITY_PUBLIC);
100 | NotificationManager manager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
101 | manager.createNotificationChannel(notificationChannel);
102 | }
103 |
104 |
105 | mNotificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
106 | Notification.Builder mynotification = new Notification.Builder(this)
107 | .setContentTitle("Android Auto GateWay")
108 | .setContentText("Running....")
109 | .setSmallIcon(R.drawable.aawifi)
110 | .setTicker("");
111 | if (Build.VERSION.SDK_INT>=26)
112 | mynotification.setChannelId(CHANNEL_ONE_ID);
113 |
114 | startForeground(1, mynotification.build());
115 |
116 | }
117 |
118 | @Override
119 | public int onStartCommand(Intent intent, int flags, int startId) {
120 |
121 | if (running) {
122 | Log.d(TAG,"Service already running");
123 | return START_STICKY;
124 | }
125 | Log.d(TAG,"Service Started");
126 | super.onStartCommand(intent, flags, startId);
127 | mAccessory = (UsbAccessory) intent.getParcelableExtra("accessory");
128 | mUsbManager = (UsbManager) getSystemService(Context.USB_SERVICE);
129 | mFileDescriptor = mUsbManager.openAccessory(mAccessory);
130 | if (mFileDescriptor != null) {
131 | fd = mFileDescriptor.getFileDescriptor();
132 | phoneInputStream = new FileInputStream(fd);
133 | phoneOutputStream = new FileOutputStream(fd);
134 | usbCompleted=false;
135 | } else {
136 | Log.e(TAG, "Cannot open usb accessory "+mAccessory.toString());
137 | stopSelf();
138 | return START_STICKY;
139 | }
140 |
141 | //Manually start AA.
142 | running=true;
143 | localCompleted = false;
144 | usbCompleted = false;
145 | usbreader = new Thread(new usbpollthread());
146 | tcpreader = new Thread(new tcppollthread());
147 | usbreader.start();
148 | tcpreader.start();
149 |
150 | return START_STICKY;
151 | }
152 |
153 | class tcppollthread implements Runnable {
154 | private ServerSocket serversocket=null;
155 |
156 | public void run() {
157 | Log.d(TAG,"tcp - run");
158 | if (listening)
159 | Log.d(TAG, "tcp - listening mode");
160 | else
161 | Log.d(TAG, "tcp - connection mode");
162 | if (ignoreipv6)
163 | Log.d(TAG, "tcp - use ipv4 addresses");
164 | else
165 | Log.d(TAG, "tcp - use ipv6 addresses");
166 |
167 | //connect or accept connection from the phone
168 | try {
169 |
170 | if (listening) {
171 | serversocket = new ServerSocket(5288, 5);
172 | serversocket.setSoTimeout(5000); //die early, die young
173 | serversocket.setReuseAddress(true);
174 | Log.d(TAG, "tcp - listening");
175 | }
176 | //get the address of the clients connected to this hotspot
177 | String[] command = {"ip", "neigh", "show", "dev", "wlan0"};
178 | Process p = Runtime.getRuntime().exec(command);
179 | BufferedReader br = new BufferedReader(
180 | new InputStreamReader(p.getInputStream()));
181 | String line;
182 | String phoneaddr = null;
183 | byte[] trigbuf = new byte[]{'S'};
184 | DatagramSocket trigger = new DatagramSocket();
185 | InetAddress addr;
186 | while ((line = br.readLine()) != null) {
187 | Log.d(TAG, "tcp - ip neigh output " + line);
188 | String[] splitted = line.split(" +");
189 | if ((splitted == null) || (splitted.length < 1)) {
190 | Log.d(TAG, "tcp - not splitted?!");
191 | continue;
192 | }
193 | boolean isipv6 = splitted[0].contains(":");
194 | if (ignoreipv6 && isipv6) {
195 | Log.d(TAG, "tcp - IPV6, ignoring");
196 | continue;
197 | }
198 | if (!ignoreipv6 && !isipv6) {
199 | Log.d(TAG, "tcp - IPV4, ignoring");
200 | continue;
201 | }
202 | addr = InetAddress.getByName(splitted[0]);
203 | if (listening) {
204 | //send to every address, only the phone with AAStarter will try to connect back
205 | Log.d(TAG, "tcp - sending trigger to " + splitted[0]);
206 | DatagramPacket trigpacket = new DatagramPacket(trigbuf, trigbuf.length, addr, 4455);
207 | trigger.send(trigpacket);
208 | } else {
209 | if (addr.isReachable(300)) {
210 | Log.d(TAG, "tcp - reachable " + splitted[0]);
211 | phoneaddr = splitted[0];
212 | break;
213 | }
214 | Log.d(TAG, "tcp - not reachable " + splitted[0]);
215 | }
216 | }
217 | if (listening) {
218 | socket = serversocket.accept();
219 | Log.d(TAG, "tcp - phone has connected back");
220 | socket.setSoTimeout(5000);
221 | } else {
222 | if (phoneaddr == null) {
223 | //no address found
224 | Log.e(TAG, "tcp - no active station found");
225 | running = false;
226 | stopSelf();
227 | } else {
228 | Log.d(TAG, "tcp - connecting to phone " + phoneaddr);
229 | socket = new Socket();
230 | socket.setSoTimeout(5000);
231 | socket.connect(new InetSocketAddress(phoneaddr, 5277), 500);
232 | Log.d(TAG, "tcp - connected");
233 | }
234 | }
235 |
236 | //at this point running could be false in non listening mode and no address found
237 | if (running) {
238 | socketoutput = socket.getOutputStream();
239 | socketinput = new DataInputStream(socket.getInputStream());
240 | socketoutput.write(new byte[]{0, 3, 0, 6, 0, 1, 0, 1, 0, 2});
241 | socketoutput.flush();
242 | byte[] recv = new byte[12];
243 | socketinput.read(recv);
244 | Log.d(TAG, "tcp - recv from phone " + bytesToHex(recv));
245 | localCompleted = true;
246 | }
247 | } catch (Exception e) {
248 | Log.e(TAG, "tcp - error opening phone " + e.getMessage());
249 | running = false;
250 | stopSelf();
251 | }
252 |
253 | //wait for usb initialization
254 | if (!usbCompleted && running)
255 | Log.d(TAG, "tcp - waiting for usb");
256 | while (!usbCompleted && running) {
257 | try {
258 | Thread.sleep(10);
259 | } catch (InterruptedException e) {
260 | Log.e(TAG, "tcp - error sleeping "+e.getMessage());
261 | }
262 | }
263 |
264 | //Looper.prepare();
265 | while (running)
266 | {
267 | try {
268 |
269 | getLocalmessage(false);
270 |
271 | } catch (Exception e) {
272 | Log.e(TAG,"tcp - in main loop "+e.getMessage());
273 | running = false;
274 | stopSelf();
275 | }
276 | }
277 |
278 | if (serversocket != null) {
279 | try {
280 | serversocket.close();
281 | } catch (IOException e) {
282 | Log.e(TAG, "tcp - closing server socket "+e.getMessage());
283 | }
284 | }
285 | Log.d(TAG,"tcp - end");
286 | stopSelf();
287 | }
288 |
289 | }
290 |
291 | class usbpollthread implements Runnable {
292 |
293 |
294 | public void run() {
295 |
296 | Log.d(TAG,"usb - run");
297 |
298 | //Looper.prepare();
299 |
300 |
301 | byte buf [] = new byte[16384];
302 | int x;
303 |
304 | try {
305 | x=phoneInputStream.read(buf);
306 | Log.d(TAG, "usb -received from usb "+bytesToHex((Arrays.copyOf(buf, x))));
307 | phoneOutputStream.write(new byte[]{0, 3, 0, 8, 0, 2, 0, 1, 0, 4, 0, 0});
308 | //tcpreader.join();
309 | usbCompleted = true;
310 | } catch (Exception e) {
311 | Log.e(TAG, "usb - error init "+e.getMessage());
312 | running = false;
313 | stopSelf();
314 | }
315 |
316 | if (!localCompleted && running)
317 | Log.d(TAG, "usb - waiting for local");
318 | while (!localCompleted && running) {
319 | try {
320 | Thread.sleep(100);
321 | } catch (InterruptedException e) {
322 | Log.e(TAG, "usb - error sleeping "+e.getMessage());
323 | }
324 | }
325 |
326 | while (running)
327 | {
328 | try {
329 | x = phoneInputStream.read(buf);
330 | processCarMessage(Arrays.copyOf(buf, x));
331 | }
332 | catch (Exception e)
333 | {
334 | Log.e(TAG,"usb - in main loop " + e.getMessage());
335 | running = false;
336 | stopSelf();
337 | }
338 |
339 | }
340 | if (mFileDescriptor!=null) {
341 | try {
342 | mFileDescriptor.close();
343 | } catch (IOException e) {
344 | Log.d(TAG, "error closing usb " + e.getMessage());
345 | }
346 | }
347 | Log.d(TAG,"usb - end");
348 | stopSelf();
349 | }
350 | };
351 |
352 | private void getLocalmessage(boolean canBeEmpty) throws IOException {
353 |
354 |
355 | int enc_len;
356 | socketinput.readFully(readbuffer,0,4);
357 | int pos=4;
358 | enc_len = (readbuffer[2] & 0xFF) << 8 | (readbuffer[3] & 0xFF);
359 | if ((int) readbuffer[1] == 9) //Flag 9 means the header is 8 bytes long (read it in a separate byte array)
360 | {
361 | pos+=4;
362 | socketinput.readFully(readbuffer,4,4);
363 | }
364 |
365 | socketinput.readFully(readbuffer,pos,enc_len);
366 | phoneOutputStream.write(Arrays.copyOf(readbuffer,enc_len+pos));
367 |
368 |
369 | }
370 |
371 | private void processCarMessage(final byte[] buf) throws IOException {
372 | socketoutput.write(buf);
373 | }
374 |
375 | @Override
376 | public void onDestroy() {
377 | running=false;
378 | mNotificationManager.cancelAll();
379 | Log.d(TAG,"service destroyed");
380 | //android.os.Process.killProcess (android.os.Process.myPid ());
381 | }
382 |
383 | private final static char[] hexArray = "0123456789ABCDEF".toCharArray();
384 | public static String bytesToHex(byte[] bytes) {
385 | char[] hexChars = new char[bytes.length * 2];
386 | for ( int j = 0; j < bytes.length; j++ ) {
387 | int v = bytes[j] & 0xFF;
388 | hexChars[j * 2] = hexArray[v >>> 4];
389 | hexChars[j * 2 + 1] = hexArray[v & 0x0F];
390 | }
391 | String aux = new String(hexChars);
392 | // Log.d("AAGateWay","ByteTohex: " + aux);
393 | return aux;
394 | }
395 |
396 | }
397 |
--------------------------------------------------------------------------------
/app/src/main/java/uk/co/borconi/emil/aagateway/MainActivity.java:
--------------------------------------------------------------------------------
1 | package uk.co.borconi.emil.aagateway;
2 |
3 |
4 | import android.content.Intent;
5 | import android.content.SharedPreferences;
6 | import android.os.Bundle;
7 | import android.preference.PreferenceManager;
8 | import android.support.v4.content.ContextCompat;
9 | import android.support.v7.app.AppCompatActivity;
10 | import android.util.Log;
11 | import android.view.View;
12 | import android.widget.Button;
13 | import android.widget.CompoundButton;
14 | import android.widget.Switch;
15 | import android.widget.ToggleButton;
16 |
17 |
18 | public class MainActivity extends AppCompatActivity {
19 |
20 |
21 |
22 | private static final String TAG = "AAGateWay";
23 | private SharedPreferences preferences;
24 |
25 |
26 | @Override
27 | protected void onCreate(Bundle savedInstanceState) {
28 | super.onCreate(savedInstanceState);
29 | setContentView(R.layout.activity_main);
30 |
31 |
32 | if (getIntent().getAction()!=null && getIntent().getAction().equalsIgnoreCase("android.intent.action.MAIN")) {
33 |
34 | preferences = PreferenceManager.getDefaultSharedPreferences(getApplicationContext());
35 |
36 | ToggleButton listenswitch = findViewById(R.id.swListening);
37 | listenswitch.setChecked(preferences.getBoolean(Preferences.LISTENING_MODE, true));
38 | listenswitch.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
39 | @Override
40 | public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
41 | SharedPreferences.Editor editor = preferences.edit()
42 | .putBoolean(Preferences.LISTENING_MODE, isChecked);
43 | editor.commit();
44 | }
45 | });
46 |
47 | ToggleButton ignoreipv6switch = findViewById(R.id.swIpMode);
48 | ignoreipv6switch.setChecked(preferences.getBoolean(Preferences.IGNORE_IPV6, true));
49 | ignoreipv6switch.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
50 | @Override
51 | public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
52 | SharedPreferences.Editor editor = preferences.edit()
53 | .putBoolean(Preferences.IGNORE_IPV6, isChecked);
54 | editor.commit();
55 | }
56 | });
57 |
58 | Button button = findViewById(R.id.exitButton);
59 | button.setOnClickListener(new View.OnClickListener() {
60 | @Override
61 | public void onClick(View view) {
62 | finish();
63 | }
64 | });
65 | }
66 |
67 | }
68 |
69 | @Override
70 | protected void onResume() {
71 | super.onResume();
72 |
73 | Intent paramIntent = getIntent();
74 | Intent i = new Intent(this, HackerService.class);
75 |
76 | if (paramIntent.getAction() != null && paramIntent.getAction().equalsIgnoreCase("android.hardware.usb.action.USB_ACCESSORY_DETACHED")) {
77 | Log.d(TAG, "USB DISCONNECTED");
78 | stopService(i);
79 | finish();
80 | } else if (paramIntent.getAction() != null && paramIntent.getAction().equalsIgnoreCase("android.hardware.usb.action.USB_ACCESSORY_ATTACHED")) {
81 | Log.d(TAG, "USB CONNECTED");
82 |
83 | // findViewById(R.id.textView).setVisibility(View.VISIBLE);
84 | //((TextView)findViewById(R.id.textView)).setText(paramIntent.getParcelableExtra("accessory").toString());
85 |
86 |
87 | if (paramIntent.getParcelableExtra("accessory") != null) {
88 | i.putExtra("accessory", paramIntent.getParcelableExtra("accessory"));
89 | ContextCompat.startForegroundService(this,i);
90 | }
91 | finish();
92 | }
93 | }
94 |
95 | @Override
96 | protected void onNewIntent(Intent paramIntent)
97 | {
98 | Log.i(TAG, "Got new intent: " + paramIntent);
99 | super.onNewIntent(paramIntent);
100 | setIntent(paramIntent);
101 | }
102 |
103 | }
104 |
--------------------------------------------------------------------------------
/app/src/main/java/uk/co/borconi/emil/aagateway/PowerConnectionReceiver.java:
--------------------------------------------------------------------------------
1 | package uk.co.borconi.emil.aagateway;
2 |
3 | import android.content.BroadcastReceiver;
4 | import android.content.Context;
5 | import android.content.Intent;
6 | import android.util.Log;
7 |
8 | public class PowerConnectionReceiver extends BroadcastReceiver {
9 | private static final String TAG = "AAGateWay";
10 |
11 | @Override
12 | public void onReceive(Context context, Intent intent) {
13 | Log.d(TAG, "power disconnected");
14 | Intent nopowerintent = new Intent(context, HackerService.class);
15 | context.stopService(nopowerintent);
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/app/src/main/java/uk/co/borconi/emil/aagateway/Preferences.java:
--------------------------------------------------------------------------------
1 | package uk.co.borconi.emil.aagateway;
2 |
3 | public class Preferences {
4 | public static final String LISTENING_MODE = "listening_mode";
5 | public static final String IGNORE_IPV6 = "ignore_ipv6";
6 | }
7 |
--------------------------------------------------------------------------------
/app/src/main/jniLibs/armeabi/libhu_jni.so:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mikeeq/aagateway/02e89d112572f0612c6c66e22e8f24a1ff7dcb01/app/src/main/jniLibs/armeabi/libhu_jni.so
--------------------------------------------------------------------------------
/app/src/main/jniLibs/x86/libhu_jni.so:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mikeeq/aagateway/02e89d112572f0612c6c66e22e8f24a1ff7dcb01/app/src/main/jniLibs/x86/libhu_jni.so
--------------------------------------------------------------------------------
/app/src/main/res/drawable-v24/ic_launcher_foreground.xml:
--------------------------------------------------------------------------------
1 |
7 |
12 |
13 |
19 |
22 |
25 |
26 |
27 |
28 |
34 |
35 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/aawifi.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mikeeq/aagateway/02e89d112572f0612c6c66e22e8f24a1ff7dcb01/app/src/main/res/drawable/aawifi.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable/hu_icon_256.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mikeeq/aagateway/02e89d112572f0612c6c66e22e8f24a1ff7dcb01/app/src/main/res/drawable/hu_icon_256.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_launcher_background.xml:
--------------------------------------------------------------------------------
1 |
2 |
7 |
10 |
15 |
20 |
25 |
30 |
35 |
40 |
45 |
50 |
55 |
60 |
65 |
70 |
75 |
80 |
85 |
90 |
95 |
100 |
105 |
110 |
115 |
120 |
125 |
130 |
135 |
140 |
145 |
150 |
155 |
160 |
165 |
170 |
171 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_main.xml:
--------------------------------------------------------------------------------
1 |
2 |
9 |
10 |
13 |
14 |
23 |
24 |
31 |
32 |
35 |
36 |
43 |
44 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-hdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mikeeq/aagateway/02e89d112572f0612c6c66e22e8f24a1ff7dcb01/app/src/main/res/mipmap-hdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-hdpi/ic_launcher_foreground.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mikeeq/aagateway/02e89d112572f0612c6c66e22e8f24a1ff7dcb01/app/src/main/res/mipmap-hdpi/ic_launcher_foreground.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-hdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mikeeq/aagateway/02e89d112572f0612c6c66e22e8f24a1ff7dcb01/app/src/main/res/mipmap-hdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-mdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mikeeq/aagateway/02e89d112572f0612c6c66e22e8f24a1ff7dcb01/app/src/main/res/mipmap-mdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-mdpi/ic_launcher_foreground.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mikeeq/aagateway/02e89d112572f0612c6c66e22e8f24a1ff7dcb01/app/src/main/res/mipmap-mdpi/ic_launcher_foreground.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-mdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mikeeq/aagateway/02e89d112572f0612c6c66e22e8f24a1ff7dcb01/app/src/main/res/mipmap-mdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mikeeq/aagateway/02e89d112572f0612c6c66e22e8f24a1ff7dcb01/app/src/main/res/mipmap-xhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xhdpi/ic_launcher_foreground.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mikeeq/aagateway/02e89d112572f0612c6c66e22e8f24a1ff7dcb01/app/src/main/res/mipmap-xhdpi/ic_launcher_foreground.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mikeeq/aagateway/02e89d112572f0612c6c66e22e8f24a1ff7dcb01/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mikeeq/aagateway/02e89d112572f0612c6c66e22e8f24a1ff7dcb01/app/src/main/res/mipmap-xxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxhdpi/ic_launcher_foreground.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mikeeq/aagateway/02e89d112572f0612c6c66e22e8f24a1ff7dcb01/app/src/main/res/mipmap-xxhdpi/ic_launcher_foreground.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mikeeq/aagateway/02e89d112572f0612c6c66e22e8f24a1ff7dcb01/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mikeeq/aagateway/02e89d112572f0612c6c66e22e8f24a1ff7dcb01/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxxhdpi/ic_launcher_foreground.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mikeeq/aagateway/02e89d112572f0612c6c66e22e8f24a1ff7dcb01/app/src/main/res/mipmap-xxxhdpi/ic_launcher_foreground.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mikeeq/aagateway/02e89d112572f0612c6c66e22e8f24a1ff7dcb01/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/app/src/main/res/values/colors.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | #3F51B5
4 | #303F9F
5 | #FF4081
6 |
7 |
--------------------------------------------------------------------------------
/app/src/main/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 | AAGateWay
3 |
4 |
--------------------------------------------------------------------------------
/app/src/main/res/values/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/app/src/main/res/values/white.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | #FFFFFF
4 |
--------------------------------------------------------------------------------
/app/src/main/res/xml/accessory_filter.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/app/src/test/java/uk/co/borconi/emil/aagateway/ExampleUnitTest.java:
--------------------------------------------------------------------------------
1 | package uk.co.borconi.emil.aagateway;
2 |
3 | import org.junit.Test;
4 |
5 | import static org.junit.Assert.*;
6 |
7 | /**
8 | * Example local unit test, which will execute on the development machine (host).
9 | *
10 | * @see Testing documentation
11 | */
12 | public class ExampleUnitTest {
13 | @Test
14 | public void addition_isCorrect() throws Exception {
15 | assertEquals(4, 2 + 2);
16 | }
17 | }
--------------------------------------------------------------------------------
/build.gradle:
--------------------------------------------------------------------------------
1 | // Top-level build file where you can add configuration options common to all sub-projects/modules.
2 |
3 | buildscript {
4 | repositories {
5 | maven {
6 | url 'https://maven.google.com'
7 | }
8 | jcenter()
9 | maven { url 'https://maven.fabric.io/public' }
10 | google()
11 | }
12 | dependencies {
13 | classpath 'com.android.tools.build:gradle:3.4.1'
14 |
15 | // NOTE: Do not place your application dependencies here; they belong
16 | // in the individual module build.gradle files
17 | }
18 | }
19 |
20 | allprojects {
21 | repositories {
22 | maven {
23 | url 'https://maven.google.com'
24 | }
25 | jcenter()
26 | maven { url 'https://maven.fabric.io/public' }
27 | }
28 | }
29 |
30 | task clean(type: Delete) {
31 | delete rootProject.buildDir
32 | }
33 |
--------------------------------------------------------------------------------
/build_in_docker.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | set -eu -o pipefail
4 |
5 | DOCKER_IMAGE=android_build
6 |
7 | docker build -t ${DOCKER_IMAGE} .
8 |
9 | docker run \
10 | --rm \
11 | -t \
12 | -v "$(pwd)":/repo \
13 | -w /repo \
14 | ${DOCKER_IMAGE} \
15 | /bin/bash -c "./gradlew assemble"
16 |
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mikeeq/aagateway/02e89d112572f0612c6c66e22e8f24a1ff7dcb01/gradle/wrapper/gradle-wrapper.jar
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.properties:
--------------------------------------------------------------------------------
1 | distributionBase=GRADLE_USER_HOME
2 | distributionPath=wrapper/dists
3 | distributionUrl=https\://services.gradle.org/distributions/gradle-5.1.1-bin.zip
4 | zipStoreBase=GRADLE_USER_HOME
5 | zipStorePath=wrapper/dists
6 |
--------------------------------------------------------------------------------
/gradlew:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env sh
2 |
3 | ##############################################################################
4 | ##
5 | ## Gradle start up script for UN*X
6 | ##
7 | ##############################################################################
8 |
9 | # Attempt to set APP_HOME
10 | # Resolve links: $0 may be a link
11 | PRG="$0"
12 | # Need this for relative symlinks.
13 | while [ -h "$PRG" ] ; do
14 | ls=`ls -ld "$PRG"`
15 | link=`expr "$ls" : '.*-> \(.*\)$'`
16 | if expr "$link" : '/.*' > /dev/null; then
17 | PRG="$link"
18 | else
19 | PRG=`dirname "$PRG"`"/$link"
20 | fi
21 | done
22 | SAVED="`pwd`"
23 | cd "`dirname \"$PRG\"`/" >/dev/null
24 | APP_HOME="`pwd -P`"
25 | cd "$SAVED" >/dev/null
26 |
27 | APP_NAME="Gradle"
28 | APP_BASE_NAME=`basename "$0"`
29 |
30 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
31 | DEFAULT_JVM_OPTS='"-Xmx64m"'
32 |
33 | # Use the maximum available, or set MAX_FD != -1 to use that value.
34 | MAX_FD="maximum"
35 |
36 | warn () {
37 | echo "$*"
38 | }
39 |
40 | die () {
41 | echo
42 | echo "$*"
43 | echo
44 | exit 1
45 | }
46 |
47 | # OS specific support (must be 'true' or 'false').
48 | cygwin=false
49 | msys=false
50 | darwin=false
51 | nonstop=false
52 | case "`uname`" in
53 | CYGWIN* )
54 | cygwin=true
55 | ;;
56 | Darwin* )
57 | darwin=true
58 | ;;
59 | MINGW* )
60 | msys=true
61 | ;;
62 | NONSTOP* )
63 | nonstop=true
64 | ;;
65 | esac
66 |
67 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
68 |
69 | # Determine the Java command to use to start the JVM.
70 | if [ -n "$JAVA_HOME" ] ; then
71 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
72 | # IBM's JDK on AIX uses strange locations for the executables
73 | JAVACMD="$JAVA_HOME/jre/sh/java"
74 | else
75 | JAVACMD="$JAVA_HOME/bin/java"
76 | fi
77 | if [ ! -x "$JAVACMD" ] ; then
78 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
79 |
80 | Please set the JAVA_HOME variable in your environment to match the
81 | location of your Java installation."
82 | fi
83 | else
84 | JAVACMD="java"
85 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
86 |
87 | Please set the JAVA_HOME variable in your environment to match the
88 | location of your Java installation."
89 | fi
90 |
91 | # Increase the maximum file descriptors if we can.
92 | if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then
93 | MAX_FD_LIMIT=`ulimit -H -n`
94 | if [ $? -eq 0 ] ; then
95 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
96 | MAX_FD="$MAX_FD_LIMIT"
97 | fi
98 | ulimit -n $MAX_FD
99 | if [ $? -ne 0 ] ; then
100 | warn "Could not set maximum file descriptor limit: $MAX_FD"
101 | fi
102 | else
103 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
104 | fi
105 | fi
106 |
107 | # For Darwin, add options to specify how the application appears in the dock
108 | if $darwin; then
109 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
110 | fi
111 |
112 | # For Cygwin, switch paths to Windows format before running java
113 | if $cygwin ; then
114 | APP_HOME=`cygpath --path --mixed "$APP_HOME"`
115 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
116 | JAVACMD=`cygpath --unix "$JAVACMD"`
117 |
118 | # We build the pattern for arguments to be converted via cygpath
119 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
120 | SEP=""
121 | for dir in $ROOTDIRSRAW ; do
122 | ROOTDIRS="$ROOTDIRS$SEP$dir"
123 | SEP="|"
124 | done
125 | OURCYGPATTERN="(^($ROOTDIRS))"
126 | # Add a user-defined pattern to the cygpath arguments
127 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then
128 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
129 | fi
130 | # Now convert the arguments - kludge to limit ourselves to /bin/sh
131 | i=0
132 | for arg in "$@" ; do
133 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
134 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
135 |
136 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
137 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
138 | else
139 | eval `echo args$i`="\"$arg\""
140 | fi
141 | i=$((i+1))
142 | done
143 | case $i in
144 | (0) set -- ;;
145 | (1) set -- "$args0" ;;
146 | (2) set -- "$args0" "$args1" ;;
147 | (3) set -- "$args0" "$args1" "$args2" ;;
148 | (4) set -- "$args0" "$args1" "$args2" "$args3" ;;
149 | (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
150 | (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
151 | (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
152 | (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
153 | (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
154 | esac
155 | fi
156 |
157 | # Escape application args
158 | save () {
159 | for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done
160 | echo " "
161 | }
162 | APP_ARGS=$(save "$@")
163 |
164 | # Collect all arguments for the java command, following the shell quoting and substitution rules
165 | eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS"
166 |
167 | # by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong
168 | if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then
169 | cd "$(dirname "$0")"
170 | fi
171 |
172 | exec "$JAVACMD" "$@"
173 |
--------------------------------------------------------------------------------
/gradlew.bat:
--------------------------------------------------------------------------------
1 | @if "%DEBUG%" == "" @echo off
2 | @rem ##########################################################################
3 | @rem
4 | @rem Gradle startup script for Windows
5 | @rem
6 | @rem ##########################################################################
7 |
8 | @rem Set local scope for the variables with windows NT shell
9 | if "%OS%"=="Windows_NT" setlocal
10 |
11 | set DIRNAME=%~dp0
12 | if "%DIRNAME%" == "" set DIRNAME=.
13 | set APP_BASE_NAME=%~n0
14 | set APP_HOME=%DIRNAME%
15 |
16 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
17 | set DEFAULT_JVM_OPTS="-Xmx64m"
18 |
19 | @rem Find java.exe
20 | if defined JAVA_HOME goto findJavaFromJavaHome
21 |
22 | set JAVA_EXE=java.exe
23 | %JAVA_EXE% -version >NUL 2>&1
24 | if "%ERRORLEVEL%" == "0" goto init
25 |
26 | echo.
27 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
28 | echo.
29 | echo Please set the JAVA_HOME variable in your environment to match the
30 | echo location of your Java installation.
31 |
32 | goto fail
33 |
34 | :findJavaFromJavaHome
35 | set JAVA_HOME=%JAVA_HOME:"=%
36 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe
37 |
38 | if exist "%JAVA_EXE%" goto init
39 |
40 | echo.
41 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
42 | echo.
43 | echo Please set the JAVA_HOME variable in your environment to match the
44 | echo location of your Java installation.
45 |
46 | goto fail
47 |
48 | :init
49 | @rem Get command-line arguments, handling Windows variants
50 |
51 | if not "%OS%" == "Windows_NT" goto win9xME_args
52 |
53 | :win9xME_args
54 | @rem Slurp the command line arguments.
55 | set CMD_LINE_ARGS=
56 | set _SKIP=2
57 |
58 | :win9xME_args_slurp
59 | if "x%~1" == "x" goto execute
60 |
61 | set CMD_LINE_ARGS=%*
62 |
63 | :execute
64 | @rem Setup the command line
65 |
66 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
67 |
68 | @rem Execute Gradle
69 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
70 |
71 | :end
72 | @rem End local scope for the variables with windows NT shell
73 | if "%ERRORLEVEL%"=="0" goto mainEnd
74 |
75 | :fail
76 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
77 | rem the _cmd.exe /c_ return code!
78 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
79 | exit /b 1
80 |
81 | :mainEnd
82 | if "%OS%"=="Windows_NT" endlocal
83 |
84 | :omega
85 |
--------------------------------------------------------------------------------
/settings.gradle:
--------------------------------------------------------------------------------
1 | include ':app'
2 |
--------------------------------------------------------------------------------