diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 18219fb2..b47e09f2 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -58,7 +58,7 @@ - + diff --git a/app/src/main/java/com/amos/flyinn/ADBActivity.java b/app/src/main/java/com/amos/flyinn/ADBActivity.java index 8ab7503a..b6941ac6 100644 --- a/app/src/main/java/com/amos/flyinn/ADBActivity.java +++ b/app/src/main/java/com/amos/flyinn/ADBActivity.java @@ -22,7 +22,7 @@ protected void onCreate(Bundle savedInstanceState) { try { Point p = new Point(); getWindowManager().getDefaultDisplay().getRealSize(p); - Demo.start(getApplicationContext(), "127.0.0.1", p); + Demo.start(getApplicationContext(), p); } catch (Exception e) { e.printStackTrace(); } diff --git a/app/src/main/java/com/amos/flyinn/ConnectionSetupActivity.java b/app/src/main/java/com/amos/flyinn/ConnectionSetupActivity.java index 1c044ba9..e3a64aa2 100644 --- a/app/src/main/java/com/amos/flyinn/ConnectionSetupActivity.java +++ b/app/src/main/java/com/amos/flyinn/ConnectionSetupActivity.java @@ -194,13 +194,12 @@ private void restartAPP() { /** * This method is to create an ADB service * - * @param addr the address where the ADB service is going to listen for connections * @return returns Daemon service to work with the ADB service */ - protected Daemon createADBService(String addr) { + protected Daemon createADBService() { Point p = new Point(); getWindowManager().getDefaultDisplay().getRealSize(p); - Daemon d = new Daemon(getApplicationContext(), addr, p); + Daemon d = new Daemon(getApplicationContext(), p); try { d.writeFakeInputToFilesystem(); d.spawn_adb(); diff --git a/app/src/main/java/com/amos/flyinn/MainActivity.java b/app/src/main/java/com/amos/flyinn/MainActivity.java index 7e2cf5b5..90170553 100644 --- a/app/src/main/java/com/amos/flyinn/MainActivity.java +++ b/app/src/main/java/com/amos/flyinn/MainActivity.java @@ -1,9 +1,5 @@ package com.amos.flyinn; -import android.app.AlertDialog; -import android.content.DialogInterface; -import android.os.StrictMode; -import android.provider.Settings; import android.Manifest; import android.app.AlertDialog; import android.content.Context; @@ -117,10 +113,10 @@ public boolean onOptionsItemSelected(MenuItem item) { System.loadLibrary("native-lib"); } - protected Daemon createADBService(String addr) { + protected Daemon createADBService() { Point p = new Point(); getWindowManager().getDefaultDisplay().getRealSize(p); - Daemon d = new Daemon(getApplicationContext(), addr, p); + Daemon d = new Daemon(getApplicationContext(), p); try { d.writeFakeInputToFilesystem(); d.spawn_adb(); @@ -146,13 +142,11 @@ public void onClick(View view) { // Example of a call to a native method connectionStatus = findViewById(R.id.connectionStatus); - String addr; try { - addr = "127.0.0.1"; while (ContextCompat.checkSelfPermission(this, Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) { ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE, Manifest.permission.READ_EXTERNAL_STORAGE}, 0); } - adbDaemon = createADBService(addr); + adbDaemon = createADBService(); } catch (Exception e) { } @@ -169,9 +163,6 @@ public void onClick(View view) { public native String stringFromJNI(); - - - private void checkForDebuggingMode() { if (Settings.Secure.getInt(this.getContentResolver(), Settings.Global.ADB_ENABLED, 0) != 1) { AlertDialog alertDialog = new AlertDialog.Builder(MainActivity.this).create(); diff --git a/app/src/main/java/com/amos/flyinn/ShowCodeActivity.java b/app/src/main/java/com/amos/flyinn/ShowCodeActivity.java index 7adc952e..3240668f 100644 --- a/app/src/main/java/com/amos/flyinn/ShowCodeActivity.java +++ b/app/src/main/java/com/amos/flyinn/ShowCodeActivity.java @@ -1,7 +1,9 @@ package com.amos.flyinn; +import android.Manifest; import android.content.Intent; import android.content.pm.PackageManager; +import android.graphics.Point; import android.os.Build; import android.os.Bundle; import android.support.annotation.CallSuper; @@ -13,6 +15,7 @@ import android.widget.Toast; import com.amos.flyinn.nearbyservice.NearbyService; +import com.amos.flyinn.summoner.Daemon; import java.util.concurrent.ThreadLocalRandom; @@ -47,18 +50,40 @@ protected void onCreate(Bundle savedInstanceState) { setContentView(R.layout.activity_show_code); display = findViewById(R.id.textView2); - if (!hasPermissions(NearbyService.getRequiredPermissions()) && - Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { + if (!hasPermissions(NearbyService.getRequiredPermissions()) && Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { requestPermissions(NearbyService.getRequiredPermissions(), REQUEST_CODE_REQUIRED_PERMISSIONS); } else { Log.w(TAG, "Could not check permissions due to version"); } + String[] perms = new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE, Manifest.permission.READ_EXTERNAL_STORAGE}; + if (!hasPermissions(perms) && Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { + requestPermissions(perms, REQUEST_CODE_REQUIRED_PERMISSIONS); + } + + try { + createADBService(); + } catch (Exception e) { + Log.d("ShowCodeActivity", "Failed to start ADB service"); + e.printStackTrace(); + } nameNum = String.valueOf(ThreadLocalRandom.current().nextInt(1000, 9998 + 1)); display.setText(nameNum); setService(); } + protected Daemon createADBService() throws Exception { + Point p = new Point(); + getWindowManager().getDefaultDisplay().getRealSize(p); + Daemon d = new Daemon(getApplicationContext(), p); + d.writeFakeInputToFilesystem(); + Log.d("ShowCodeActivity", "Wrote to FS"); + Log.d("ShowCodeActivity", "Going to spawn ADB service"); + d.spawn_adb(); + Log.d("ShowCodeActivity", "Spawned ADB service"); + return d; + } + @Override public void onResume() { super.onResume(); @@ -75,8 +100,8 @@ protected void onDestroy() { /** * Handles user acceptance (or denial) of our permission request. * - * @param requestCode The request code passed in requestPermissions() - * @param permissions Permissions that must be granted to run nearby connections + * @param requestCode The request code passed in requestPermissions() + * @param permissions Permissions that must be granted to run nearby connections * @param grantResults Results of granting permissions */ @CallSuper diff --git a/app/src/main/java/com/amos/flyinn/nearbyservice/NearbyService.java b/app/src/main/java/com/amos/flyinn/nearbyservice/NearbyService.java index 9854f6a0..a9995543 100644 --- a/app/src/main/java/com/amos/flyinn/nearbyservice/NearbyService.java +++ b/app/src/main/java/com/amos/flyinn/nearbyservice/NearbyService.java @@ -1,7 +1,5 @@ package com.amos.flyinn.nearbyservice; -import android.annotation.TargetApi; -import android.app.Activity; import android.app.IntentService; import android.app.Notification; import android.app.NotificationChannel; @@ -11,21 +9,19 @@ import android.content.Context; import android.content.Intent; import android.os.Build; -import android.os.Handler; +import android.os.Parcelable; import android.support.annotation.Nullable; import android.support.v4.app.NotificationCompat; import android.util.Log; - import com.amos.flyinn.ConnectionSetupActivity; -import com.amos.flyinn.R; import com.amos.flyinn.ShowCodeActivity; +import com.amos.flyinn.summoner.ADBService; +import com.amos.flyinn.summoner.ConnectionSigleton; import com.google.android.gms.nearby.connection.Payload; import com.google.android.gms.nearby.connection.PayloadTransferUpdate; -import java.util.Timer; -import java.util.TimerTask; -import java.util.concurrent.ThreadLocalRandom; +import java.util.Objects; /** * Manage nearby connections with a server. @@ -35,7 +31,6 @@ * initiate a connection over nearby. */ public class NearbyService extends IntentService { - public static final String TAG = NearbyService.class.getPackage().getName(); public static final String ACTION_START = "nearby_start"; @@ -72,19 +67,19 @@ public int onStartCommand(@Nullable Intent intent, int flags, int startId) { /** * Create a notification channel. - * + *

* Notifications are organized into different channels to theoretically enable the user to * individually set what they want to be informed about. - * + *

* This is required since Android 8. */ private void createChannel() { - NotificationManager mgr= - (NotificationManager)getSystemService(NOTIFICATION_SERVICE); - if (Build.VERSION.SDK_INT>=Build.VERSION_CODES.O && - mgr.getNotificationChannel(CHANNEL_ID)==null) { + NotificationManager mgr = + (NotificationManager) getSystemService(NOTIFICATION_SERVICE); + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O && + mgr.getNotificationChannel(CHANNEL_ID) == null) { - NotificationChannel c=new NotificationChannel(CHANNEL_ID, + NotificationChannel c = new NotificationChannel(CHANNEL_ID, "flyinn_channel", NotificationManager.IMPORTANCE_HIGH); c.enableLights(true); @@ -96,8 +91,9 @@ private void createChannel() { /** * Create a sticky notification that won't go away. + * * @param message String message shown in the notification. - * @param target Optional target intent to switch to after tapping the notification. + * @param target Optional target intent to switch to after tapping the notification. * @return */ private Notification buildForegroundNotification(String message, @Nullable Intent target) { @@ -127,6 +123,7 @@ private void raiseNotification(Notification notification) { /** * Create or update shown notification. + * * @param message */ public void notify(String message) { @@ -154,6 +151,7 @@ public void notify(String message) { /** * Activate the given activity + * * @param cls Class of the target activity */ private void switchActivity(Class cls) { @@ -168,13 +166,14 @@ public NearbyState getServiceState() { /** * Set state of the nearby service. This is used by the nearby server. + * * @param state * @param message */ public void setServiceState(NearbyState state, @Nullable String message) { // do extra things if we are switching state if (serviceState != state) { - switch(serviceState) { + switch (serviceState) { case CONNECTING: switchActivity(ConnectionSetupActivity.class); break; @@ -209,6 +208,15 @@ public void handleResponse(boolean error, String message) { public void handlePayload(Payload payload) { Log.d(TAG, "Received payload"); + if (payload.asStream() == null) { + Log.wtf("AAAAAAAAAAAAAAAAAAA", "Payload is null!"); + return; + } + Intent i = new Intent(this, ADBService.class); + i.setAction("stream"); + ConnectionSigleton.getInstance().inputStream = Objects.requireNonNull(payload.asStream()).asInputStream(); + startService(i); + Log.d(TAG, "Send payload to activity"); } public void handlePayloadTransferUpdate(PayloadTransferUpdate update) { diff --git a/app/src/main/java/com/amos/flyinn/summoner/ADBService.java b/app/src/main/java/com/amos/flyinn/summoner/ADBService.java index 32185f03..1cca9b43 100644 --- a/app/src/main/java/com/amos/flyinn/summoner/ADBService.java +++ b/app/src/main/java/com/amos/flyinn/summoner/ADBService.java @@ -2,16 +2,18 @@ import android.app.IntentService; import android.content.Intent; +import android.util.Base64; import android.util.Log; -import com.tananaev.adblib.AdbBase64; +import com.google.android.gms.common.util.IOUtils; import com.tananaev.adblib.AdbConnection; import com.tananaev.adblib.AdbCrypto; import com.tananaev.adblib.AdbStream; import java.io.IOException; +import java.io.InputStream; import java.net.Socket; -import java.security.NoSuchAlgorithmException; +import java.util.Objects; /** * Background service controlling the start of fakeinputlib via an adb shell. @@ -30,62 +32,113 @@ public ADBService() { super("ADBService"); } + @Override + public void onCreate() { + super.onCreate(); + Log.d("ADBService", "Only called once in a lifetime!"); + } + /** * Create a socket connection to use adb over network with the local phone. + * * @return - * @throws IOException - * All errors resulting in us not being able to connect to ADB over network. + * @throws IOException All errors resulting in us not being able to connect to ADB over network. */ protected AdbConnection connectNetworkADB() throws IOException { AdbConnection connection; try { Socket socket = new Socket("127.0.0.1", 5555); - AdbCrypto crypto = AdbCrypto.generateAdbKeyPair(new AdbBase64() { - @Override - public String encodeToString(byte[] data) { - return android.util.Base64.encodeToString(data, 16); - } + AdbCrypto crypto = AdbCrypto.generateAdbKeyPair(data -> { + String s = Base64.encodeToString(data, 16).replace("\n", ""); + Log.d("ADBService", "New key is" + s); + return s; }); + Log.d("ADBService", "Acquiring connection to port :5555"); connection = AdbConnection.create(socket, crypto); + Log.d("ADBService", "Trying to connect to ADB session"); connection.connect(); } catch (Exception err) { + Log.d("ADBService", "Failed to connect to ADB"); + Log.wtf("ADBService", err); throw new IOException("Could not start fakeinputlib"); } + Log.d("ADBService", "Got the ADB connection"); return connection; } /** * Run a command using adb shell. - * @param connection - * ADB connection used to spawn command on. - * @param command - * Custom command to run - * @throws IOException - * Issues in running the command correctly. + * + * @param connection ADB connection used to spawn command on. + * @param command Custom command to run + * @throws IOException Issues in running the command correctly. */ - protected void spawnApp(AdbConnection connection, String command) throws IOException { + protected void spawnApp(AdbConnection connection, String command) throws Exception { if (connection == null) { throw new IOException("Connection is null"); } Log.d("AppDaemon", "Spawning the app"); try { AdbStream stream = connection.open(command); - while (true) - stream.read(); - } catch (InterruptedException err) { - // Do nothing on interrupts for now + new Thread(() -> { + try { + for (; ; ) { + Log.d("AppDaemon", "Read loop"); + stream.read(); + } + } catch (Exception e) { + Log.d("AppDaemon", "Failed the read loop"); + e.printStackTrace(); + } + Log.d("AppDaemon", "Stopping the App"); + }).start(); + } catch (Exception e) { + Log.d("AppDaemon", "Failed to satart listener", e); + throw e; } } /** * Start the adb shell process. + * * @param workIntent */ @Override protected void onHandleIntent(Intent workIntent) { + Log.d("ADBService", "Got intent"); + if (workIntent.getStringExtra("cmd") != null && !"".equals(workIntent.getStringExtra("cmd"))) { + try { + Log.d("ADBService", "Got create intent"); + AdbConnection connection = connectNetworkADB(); + spawnApp(connection, workIntent.getStringExtra("cmd")); + Log.d("ADBService", "Launched adb connection"); + } catch (Exception e) { + Log.d("ADBService", "Failed to start the adb service", e); + } + return; + } + + Log.d("ADBService", "Get action"); try { - AdbConnection connection = connectNetworkADB(); - spawnApp(connection, workIntent.getStringExtra("cmd")); - } catch (Exception e) {} + Log.d("ADBService", workIntent.getAction()); + switch (Objects.requireNonNull(workIntent.getAction())) { + case "stream": + Log.d("ADBService", "Start proxy..."); + Socket s = new Socket("127.0.0.1", 1337); + Log.d("ADBService", "Proxy connected"); + InputStream ss = ConnectionSigleton.getInstance().inputStream; + new Thread(() -> { + try { + Log.d("ADBService", "Proxy piping..."); + IOUtils.copyStream(ss, s.getOutputStream()); + Log.d("ADBService", "Proxy done piping"); + } catch (Exception e) { + Log.d("ADBService", "Failed to pipe", e); + } + }).start(); + } + } catch (Exception e) { + Log.d("ADBService", "Failed to connect to ADB", e); + } } } diff --git a/app/src/main/java/com/amos/flyinn/summoner/ConnectionSigleton.java b/app/src/main/java/com/amos/flyinn/summoner/ConnectionSigleton.java new file mode 100644 index 00000000..265b8de7 --- /dev/null +++ b/app/src/main/java/com/amos/flyinn/summoner/ConnectionSigleton.java @@ -0,0 +1,15 @@ +package com.amos.flyinn.summoner; + +import java.io.InputStream; + +public class ConnectionSigleton { + private static final ConnectionSigleton ourInstance = new ConnectionSigleton(); + public InputStream inputStream; + + public static ConnectionSigleton getInstance() { + return ourInstance; + } + + private ConnectionSigleton() { + } +} diff --git a/app/src/main/java/com/amos/flyinn/summoner/Daemon.java b/app/src/main/java/com/amos/flyinn/summoner/Daemon.java index eae1f5f5..c15517e2 100644 --- a/app/src/main/java/com/amos/flyinn/summoner/Daemon.java +++ b/app/src/main/java/com/amos/flyinn/summoner/Daemon.java @@ -9,6 +9,7 @@ import com.amos.flyinn.R; import java.io.File; +import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; @@ -16,15 +17,19 @@ /** * Handles deployment of the fakeinputlib package. - * + *

* fakeinputlib is a separate java binary which is run with adb debugging permissions to * allow injection of input events into other applications. This daemon controls copying the * fakeinputlib binary to a specified location and its execution over adb over network. */ public class Daemon { - private final String FAKE_INPUT_SERVER_PATH = Environment.getExternalStorageDirectory() + "/Android/data/flyinn_fakeinputlib.jar"; + private final String[] WRITE_LOCATIONS = { + Environment.getExternalStorageDirectory() + "/Android/data/flyinn_fakeinputlib.jar", + "/sdcard/Android/data/flyinn_fakeinputlib.jar", + }; + private final String FILE_LOCATION = "/sdcard/Android/data/flyinn_fakeinput.jar"; // NOTE: cant use the FAKE_INPUT_SERVER_PATH as this will lead to permission issues, use "/sdcard/", which is a symlink. - private final String SHELL_FAKE_INPUT_NOHUP_COMMAND = "shell:CLASSPATH=/sdcard/Android/data/flyinn_fakeinputlib.jar app_process / com.amos.fakeinputlib.Main %s %d %d"; + private final String SHELL_FAKE_INPUT_NOHUP_COMMAND = "shell:CLASSPATH=/sdcard/Android/data/flyinn_fakeinputlib.jar app_process / com.amos.fakeinputlib.Main %d %d"; //private final String CMD = "shell:CLASSPATH=%%s nohup app_process / com.amos.fakeinputlib.Main %s %d %d"; private final String execCMD; private Context context; @@ -34,50 +39,56 @@ public class Daemon { /** * Create a new Daemon instance. * - * @param context - * Application context. Used to get application binary. - * @param addr - * Server address. This will be passed as a commandline argument to the fakeinputlib binary. - * @param screenDimensions - * Screen size including status bar and navbar. + * @param context Application context. Used to get application binary. + * @param screenDimensions Screen size including status bar and navbar. */ - public Daemon(Context context, String addr, Point screenDimensions) { - execCMD = String.format(Locale.ENGLISH, SHELL_FAKE_INPUT_NOHUP_COMMAND, addr, screenDimensions.x, screenDimensions.y); - Log.d("AdbDaemon", this.execCMD); + public Daemon(Context context, Point screenDimensions) { + execCMD = String.format(Locale.ENGLISH, SHELL_FAKE_INPUT_NOHUP_COMMAND, screenDimensions.x, screenDimensions.y); + Log.d("AdbDaemon", "Generated cmd: " + this.execCMD); this.context = context; } /** * Copy fakeinputlib binary from APK to local directory. + * * @throws IOException */ public void writeFakeInputToFilesystem() throws IOException { InputStream in = this.context.getResources().openRawResource(R.raw.fakeinputlib); + for (String destination : WRITE_LOCATIONS) + try { + File fpath = new File(destination); + FileOutputStream out = new FileOutputStream(fpath.toString()); - File fpath = new File(FAKE_INPUT_SERVER_PATH); - FileOutputStream out = new FileOutputStream(fpath.toString()); - - byte[] buff = new byte[2048]; - try { - for (int read; (read = in.read(buff)) > 0; ) { - out.write(buff, 0, read); + byte[] buff = new byte[2048]; + for (int read; (read = in.read(buff)) > 0; ) { + out.write(buff, 0, read); + } + binaryPath = fpath.toString(); + in.close(); + out.close(); + Log.d("AdbDaemon", "Wrote fakeinputlib bin to file system " + destination); + return; + } catch (FileNotFoundException ignored) { + Log.d("AdbDaemon", "Failed to write fakeinputlib bin to " + destination); + continue; } - binaryPath = fpath.toString(); - } finally { - in.close(); - out.close(); - } + + throw new IOException(); } /** * Start ADBService, which will call fakeinputlib on commandline. This is necessary in order to * keep fakeinputlib alive even when the application itself is closed. + * * @throws Exception */ public void spawn_adb() { Intent i = new Intent(context, ADBService.class); i.putExtra("cmd", execCMD); + Log.d("AdbDaemon", "Spawn ADB intent service"); + context.startService(i); } } diff --git a/app/src/main/java/com/amos/flyinn/summoner/Demo.java b/app/src/main/java/com/amos/flyinn/summoner/Demo.java index 5dc9a1fb..dbfdc31a 100644 --- a/app/src/main/java/com/amos/flyinn/summoner/Demo.java +++ b/app/src/main/java/com/amos/flyinn/summoner/Demo.java @@ -23,13 +23,13 @@ private static void periodicNagging(FakeInputSender s) throws IOException, Inter } - public static void start(Context context, String addr, Point p) { - Daemon d = new Daemon(context, addr, p); + public static void start(Context context, Point p) { + Daemon d = new Daemon(context, p); FakeInputSender s = new FakeInputSender(); try { d.writeFakeInputToFilesystem(); d.spawn_adb(); - s.connect(addr); + s.connect(); periodicNagging(s); } catch (Exception e) { e.printStackTrace(); diff --git a/app/src/main/java/com/amos/flyinn/summoner/FakeInputSender.java b/app/src/main/java/com/amos/flyinn/summoner/FakeInputSender.java index 6a1a2093..10f8f040 100644 --- a/app/src/main/java/com/amos/flyinn/summoner/FakeInputSender.java +++ b/app/src/main/java/com/amos/flyinn/summoner/FakeInputSender.java @@ -15,8 +15,8 @@ public class FakeInputSender { public FakeInputSender() { } - public void connect(String addr) throws Exception { - Socket socket = new Socket(addr, 1337); + public void connect() throws Exception { + Socket socket = new Socket("127.0.0.1", 1337); this.output = new ObjectOutputStream(socket.getOutputStream()); } diff --git a/app/src/test/java/com/amos/flyinn/summoner/DaemonTest.java b/app/src/test/java/com/amos/flyinn/summoner/DaemonTest.java index ce1054d2..98aa0421 100644 --- a/app/src/test/java/com/amos/flyinn/summoner/DaemonTest.java +++ b/app/src/test/java/com/amos/flyinn/summoner/DaemonTest.java @@ -23,7 +23,7 @@ public class DaemonTest { */ @Test public void spawn_adbHappypathTest() { - Daemon d = new Daemon(context, "127.0.0.1", new Point(0, 0)); + Daemon d = new Daemon(context, new Point(0, 0)); d.spawn_adb(); } @@ -32,7 +32,7 @@ public void spawn_adbHappypathTest() { */ @Test(expected = NullPointerException.class) public void spawn_adbNoContextTest() { - Daemon d = new Daemon(null, "127.0.0.1", new Point(0, 0)); + Daemon d = new Daemon(null, new Point(0, 0)); d.spawn_adb(); } @@ -42,7 +42,7 @@ public void spawn_adbNoContextTest() { */ @Test(expected = IOException.class) public void writeFakeInputToFilesystem() throws IOException { - Daemon d = new Daemon(context, "127.0.0.1", new Point(0, 0)); + Daemon d = new Daemon(context, new Point(0, 0)); d.writeFakeInputToFilesystem(); } } \ No newline at end of file diff --git a/fakeinputlib/src/main/java/com/amos/fakeinputlib/FakeInputReceiver.java b/fakeinputlib/src/main/java/com/amos/fakeinputlib/FakeInputReceiver.java index d4288745..1c51e480 100644 --- a/fakeinputlib/src/main/java/com/amos/fakeinputlib/FakeInputReceiver.java +++ b/fakeinputlib/src/main/java/com/amos/fakeinputlib/FakeInputReceiver.java @@ -7,6 +7,7 @@ import java.io.IOException; import java.io.ObjectInputStream; +import java.net.ServerSocket; import java.net.Socket; class FakeInputReceiver { @@ -23,12 +24,14 @@ class FakeInputReceiver { this.maxY = maxY; } - void connectToHost(String addr) throws Exception { + void connectToHost() throws Exception { + ServerSocket ss; Socket fd = null; for (int i = 0; i < 5; i++) { - Log.d("FakeInput", "Trying to connect to the host " + addr); + Log.d("FakeInput", "Listening to peers"); try { - fd = new Socket(addr, 1337); + ss = new ServerSocket( 1337); + fd = ss.accept(); } catch (Exception e) { e.printStackTrace(); @@ -64,7 +67,7 @@ private void runEvalLoop(FakeInput handler, Socket connection) throws IOExceptio continue; } - Log.d("FakeInput", "Got Event: "+e.toString()); + Log.d("FakeInput", "Got Event: " + e.toString()); MotionEvent ev = e.getConstructedMotionEvent(this.maxX, this.maxY); Log.d("FakeInput", String.format("Event: (%f, %f, %f, %f)", ev.getX(), ev.getY(), ev.getRawX(), ev.getRawX())); diff --git a/fakeinputlib/src/main/java/com/amos/fakeinputlib/Main.java b/fakeinputlib/src/main/java/com/amos/fakeinputlib/Main.java index eee6b3da..b02d0544 100644 --- a/fakeinputlib/src/main/java/com/amos/fakeinputlib/Main.java +++ b/fakeinputlib/src/main/java/com/amos/fakeinputlib/Main.java @@ -4,9 +4,13 @@ public class Main { public static void main(String[] in) throws Exception { - FakeInputReceiver server = new FakeInputReceiver(new FakeInput(), Integer.parseInt(in[1]), Integer.parseInt(in[2])); - Log.d("FakeInput", "Starting server"); - server.connectToHost(in[0]); - Log.d("FakeInput", "Stopping Server"); + Log.d("FakeInput", "Start bin"); + FakeInput handler = new FakeInput(); + FakeInputReceiver server = new FakeInputReceiver(handler, Integer.parseInt(in[0]), Integer.parseInt(in[1])); + while (true) { + Log.d("FakeInput", "Starting server"); + server.connectToHost(); + Log.d("FakeInput", "Stopping Server"); + } } } \ No newline at end of file diff --git a/server/build.gradle b/server/build.gradle index 5562205b..d235975c 100644 --- a/server/build.gradle +++ b/server/build.gradle @@ -64,27 +64,29 @@ dependencies { implementation 'com.android.support:appcompat-v7:28.0.0' implementation 'com.android.support.constraint:constraint-layout:1.1.3' implementation 'com.android.support:design:28.0.0' - testImplementation 'junit:junit:4.12' - testImplementation 'org.robolectric:robolectric:4.0.2' - androidTestImplementation 'androidx.test:core:1.0.0' - androidTestImplementation 'androidx.test:runner:1.1.0' - androidTestImplementation 'androidx.test:rules:1.1.0' implementation 'com.android.support:support-media-compat:28.0.0' implementation 'com.android.support:support-v4:28.0.0' - implementation 'org.webrtc:google-webrtc:1.0.22672' implementation "org.java-websocket:Java-WebSocket:1.3.9" - + implementation 'com.android.support:preference-v7:28.0.0' implementation 'com.google.android.gms:play-services-nearby:16.0.0' embeddedCompileOnly 'com.google.android.things:androidthings:1.0' - testImplementation 'androidx.test:core:1.0.0' - testImplementation 'org.mockito:mockito-core:1.10.19' + testImplementation 'junit:junit:4.12' + testImplementation 'org.robolectric:robolectric:4.0.2' + testImplementation 'androidx.test:core:1.1.0' testImplementation 'org.json:json:20160810' + testImplementation 'org.mockito:mockito-core:1.10.19' + testImplementation "org.powermock:powermock-module-junit4:1.6.6" + testImplementation "org.powermock:powermock-module-junit4-rule:1.6.6" + testImplementation "org.powermock:powermock-api-mockito:1.6.6" + testImplementation "org.powermock:powermock-classloading-xstream:1.6.6" // org.json is included with Android, but Android.jar can not be used from unit tests - implementation 'com.android.support:preference-v7:28.0.0' + androidTestImplementation 'androidx.test:core:1.1.0' + androidTestImplementation 'androidx.test:runner:1.1.1' + androidTestImplementation 'androidx.test:rules:1.1.1' } task prePreBuild { diff --git a/server/src/main/AndroidManifest.xml b/server/src/main/AndroidManifest.xml index e1449139..e6216081 100644 --- a/server/src/main/AndroidManifest.xml +++ b/server/src/main/AndroidManifest.xml @@ -28,17 +28,6 @@ android:supportsRtl="true" android:theme="@style/AppTheme"> - - - - - - - - + diff --git a/server/src/main/java/com/amos/server/ConnectToClientActivity.java b/server/src/main/java/com/amos/server/ConnectToClientActivity.java index cf2230d2..677a00b2 100644 --- a/server/src/main/java/com/amos/server/ConnectToClientActivity.java +++ b/server/src/main/java/com/amos/server/ConnectToClientActivity.java @@ -17,24 +17,7 @@ import android.widget.TextView; import android.widget.Toast; -import com.google.android.gms.nearby.Nearby; -import com.google.android.gms.nearby.connection.ConnectionInfo; -import com.google.android.gms.nearby.connection.ConnectionLifecycleCallback; -import com.google.android.gms.nearby.connection.ConnectionResolution; -import com.google.android.gms.nearby.connection.ConnectionsClient; -import com.google.android.gms.nearby.connection.ConnectionsStatusCodes; -import com.google.android.gms.nearby.connection.DiscoveredEndpointInfo; -import com.google.android.gms.nearby.connection.DiscoveryOptions; -import com.google.android.gms.nearby.connection.EndpointDiscoveryCallback; -import com.google.android.gms.nearby.connection.Payload; -import com.google.android.gms.nearby.connection.PayloadCallback; -import com.google.android.gms.nearby.connection.PayloadTransferUpdate; -import com.google.android.gms.nearby.connection.Strategy; - -import java.security.SecureRandom; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; +import com.amos.server.nearby.ServerConnection; public class ConnectToClientActivity extends Activity { @@ -49,224 +32,40 @@ public class ConnectToClientActivity extends Activity { private static final int REQUEST_CODE_REQUIRED_PERMISSIONS = 1; - /** 1-to-1 since a device will be connected to only one other device at most. */ - private static final Strategy STRATEGY = Strategy.P2P_POINT_TO_POINT; - - /** Connection manager for the connection to FlyInn clients. */ - protected ConnectionsClient connectionsClient; - - private final String clientName = generateName(5); - private String clientID; - private String clientNameNow; - - /** Toast to publish user notifications */ - private Toast mToast; - - /** List of all discovered servers by name, continuously updated. */ - private List clients = new ArrayList<>(); - - /** Maps server names to their nearby connection IDs. */ - private HashMap clientNamesToIDs = new HashMap<>(); - - /** Maps server IDs to their nearby connection names. */ - private HashMap clientIDsToNames = new HashMap<>(); + private ServerConnection connection = ServerConnection.getInstance(); /** Tag for logging purposes. */ private static final String TAG = "ClientNearbyConnection"; - - - - /** - * Obtain data from clientID/clientName and data transfer information via this handle. - */ - private final PayloadCallback payloadCallback = - new PayloadCallback() { - @Override - public void onPayloadReceived(String endpointId, Payload payload) { - Log.d(TAG, "Payload received"); - } - - @Override - public void onPayloadTransferUpdate(String endpointId, PayloadTransferUpdate update) { - Log.d(TAG, "Payload transfer update"); - } - }; - - - /** - * Handling of discovered endpoints (servers). Adds new endpoints to servers data maps/list, - * and removes lost endpoints. - */ - private final EndpointDiscoveryCallback endpointDiscoveryCallback = - new EndpointDiscoveryCallback() { - @Override - public void onEndpointFound(String endpointId, DiscoveredEndpointInfo info) { - // discovered a server, add to data maps - String endpointName = info.getEndpointName(); - - if (!(clientIDsToNames.containsKey(endpointId) - || clientNamesToIDs.containsKey(endpointName))) { - clients.add(endpointName); - clientNamesToIDs.put(endpointName, endpointId); - clientIDsToNames.put(endpointId, endpointName); - Log.i(TAG, clientName + " discovered endpoint " + endpointId + " with name " + endpointName); - - } else { - // this should not happen - while (clients.remove(endpointName)) {} - clients.add(endpointName); - clientIDsToNames.put(endpointId, endpointName); - clientNamesToIDs.put(endpointName, endpointId); - Log.i(TAG, clientName + " rediscovered endpoint " + endpointId + " with name " + endpointName); - } - } - - @Override - public void onEndpointLost(String endpointId) { - // previously discovered server is no longer reachable, remove from data maps - String lostEndpointName = clientIDsToNames.get(endpointId); - clientIDsToNames.remove(endpointId); - clientNamesToIDs.remove(lostEndpointName); - Log.i(TAG, clientName + " lost discovered endpoint " + endpointId); - } - }; - - - /** - * Callbacks for connections to other devices. - * Includes token authentication and connection handling. - */ - private final ConnectionLifecycleCallback connectionLifecycleCallback = - new ConnectionLifecycleCallback() { - @Override - public void onConnectionInitiated(String endpointId, ConnectionInfo connectionInfo) { - Log.i(TAG, "Connection initiated to " + endpointId); - - if (endpointId.equals(clientID)) { - connectionsClient.acceptConnection(endpointId, payloadCallback); - } else { - // initiated connection is not with server selected by user - connectionsClient.rejectConnection(endpointId); - Log.i(TAG, "Connection rejected to non-selected server " - + endpointId); - } - } - - @Override - public void onConnectionResult(String endpointId, ConnectionResolution result) { - switch (result.getStatus().getStatusCode()) { - - case ConnectionsStatusCodes.STATUS_OK: - // successful connection with server - Log.i(TAG, "Connected with " + endpointId); - mToast.setText(R.string.nearby_connection_success); - mToast.show(); - connectedToApp(); - break; - - case ConnectionsStatusCodes.STATUS_CONNECTION_REJECTED: - // connection was rejected by one side (or both) - Log.i(TAG, "Connection rejected with " + endpointId); - mToast.setText(R.string.nearby_connection_rejected); - mToast.show(); - clientNameNow = null; - clientID = null; - break; - - case ConnectionsStatusCodes.STATUS_ERROR: - // connection was lost - Log.w(TAG, "Connection lost: " + endpointId); - mToast.setText(R.string.nearby_connection_error); - mToast.show(); - clientNameNow = null; - clientID = null; - break; - - default: - // unknown status code. we shouldn't be here - Log.e(TAG, "Unknown error when attempting to connect with " - + endpointId); - mToast.setText(R.string.nearby_connection_error); - mToast.show(); - clientNameNow = null; - clientID = null; - } - } - - @Override - public void onDisconnected(String endpointId) { - // disconnected from server - Log.i(TAG, "Disconnected from " + endpointId); - mToast.setText(R.string.nearby_disconnected); - mToast.show(); - clearServerData(); - finish(); - } - }; - - - - private void requestConnectionWithClient(String code){ - - String searchedClientName = null; - for (String clientName : clients){ - if(clientName.endsWith(code)) - { - searchedClientName = clientName; - break; - } - } - - if (searchedClientName == null) - { - Toast.makeText(this,"The code given was not found. Please try again",Toast.LENGTH_LONG).show(); - return; - } - - - String endpoint = clientNamesToIDs.get(searchedClientName); - clientID = endpoint; - - - connectionsClient.requestConnection(searchedClientName,endpoint,connectionLifecycleCallback); - - - - } - @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_connect_to_client); EditText text = findViewById(R.id.connect_editText); - text.setOnEditorActionListener(new TextView.OnEditorActionListener() { - @Override - public boolean onEditorAction(TextView v, int actionId, KeyEvent event) { - if (actionId == EditorInfo.IME_ACTION_DONE) { - String name = v.getText().toString(); // Get the String - requestConnectionWithClient(name); - return true; - } - return false; - } - }); - - - if (!hasPermissions(this, REQUIRED_PERMISSIONS) && - Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { - requestPermissions(REQUIRED_PERMISSIONS, REQUEST_CODE_REQUIRED_PERMISSIONS); - } else { - Log.w(TAG, "Could not check permissions due to version"); - } - - connectionsClient = Nearby.getConnectionsClient(this); - mToast = Toast.makeText(this, "", Toast.LENGTH_SHORT); - - - startDiscovering(); + checkPermissions(); + // Ensure survival for life of entire application + connection.init(getApplicationContext()); + connection.discover(); + text.setOnEditorActionListener( + (TextView v, int actionId, KeyEvent event) -> { + if (actionId == EditorInfo.IME_ACTION_DONE) { + String name = v.getText().toString(); // Get the String + toConnectionSetup(name); + return true; + } + return false; + }); + } + /** + * Switch to connection setup activity + */ + private void toConnectionSetup(String name) { + Intent intent = new Intent(this, ConnectionSetupServerActivity.class); + intent.setAction("connect"); + intent.putExtra("name", name); + startActivity(intent); } /** @@ -277,12 +76,7 @@ protected void onStart() { super.onStart(); // user may have changed permissions - if (!hasPermissions(this, REQUIRED_PERMISSIONS) && - Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { - requestPermissions(REQUIRED_PERMISSIONS, REQUEST_CODE_REQUIRED_PERMISSIONS); - } else { - Log.w(TAG, "Could not check permissions due to version"); - } + checkPermissions(); } /** @@ -291,74 +85,30 @@ protected void onStart() { */ @Override protected void onDestroy() { - connectionsClient.stopDiscovery(); - connectionsClient.stopAllEndpoints(); - clearServerData(); super.onDestroy(); + connection.abort(); } - /** - * Clears all servers map data as well as serverName/serverID and starts discovery - */ - private void startDiscovering() { - clearServerData(); - - DiscoveryOptions discoveryOptions = - new DiscoveryOptions.Builder().setStrategy(STRATEGY).build(); - - connectionsClient.startDiscovery("com.amos.server", endpointDiscoveryCallback, - discoveryOptions) - .addOnSuccessListener( (Void unused) -> { - // started searching for servers successfully - Log.i(TAG, "Discovering connections on " + clientName); - mToast.setText(R.string.nearby_discovering_success); - mToast.show(); - }) - .addOnFailureListener( (Exception e) -> { - // unable to start discovery - Log.e(TAG, "Unable to start discovery on " + clientName); - mToast.setText(R.string.nearby_discovering_error); - mToast.show(); - finish(); - }); - } - - /** - * Clears serverName/serverID and all server data maps as well as the servers list - */ - private void clearServerData() { - clients.clear(); - clientIDsToNames.clear(); - clientNamesToIDs.clear(); - clientID = null; - clientNameNow = null; - } - - /** - * Handle established connection with app. - * - * Clears servers data maps, stops discovery of new servers and adds close connection button - */ - private void connectedToApp() { - connectionsClient.stopDiscovery(); - clients.clear(); - clientNamesToIDs.clear(); - clientIDsToNames.clear(); - - // Start setting up a connection with the other side - Intent intent = new Intent(this, ConnectionSetupServerActivity.class); - intent.putExtra("endpointId", clientID); - startActivity(intent); + private void checkPermissions() { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { + if (!hasPermissions(this)) { + requestPermissions(REQUIRED_PERMISSIONS, REQUEST_CODE_REQUIRED_PERMISSIONS); + } else { + Log.d(TAG, "Permissions are ok."); + } + } else { + Log.w(TAG, "Could not check permissions due to version"); + toast("Could not check permissions due to version"); + } } /** * Determines whether the FlyInn server app has the necessary permissions to run nearby. * @param context Checks the permissions against this context/application environment - * @param permissions The permissions to be checked * @return True if the app was granted all the permissions, false otherwise */ - private static boolean hasPermissions(Context context, String[] permissions) { - for (String permission : permissions) { + private static boolean hasPermissions(Context context) { + for (String permission : ConnectToClientActivity.REQUIRED_PERMISSIONS) { if (ContextCompat.checkSelfPermission(context, permission) != PackageManager.PERMISSION_GRANTED) { return false; @@ -367,6 +117,11 @@ private static boolean hasPermissions(Context context, String[] permissions) { return true; } + private void toast(String message) { + Toast toast = Toast.makeText(this, message, Toast.LENGTH_SHORT); + toast.show(); + } + /** * Handles user acceptance (or denial) of our permission request. * @param requestCode The request code passed in requestPermissions() @@ -387,31 +142,11 @@ public void onRequestPermissionsResult( if (grantResult == PackageManager.PERMISSION_DENIED) { Log.w(TAG, "Permissions necessary for " + "Nearby Connection were not granted."); - mToast.setText(R.string.nearby_missing_permissions); - mToast.show(); + toast("Permissions are missing for nearby"); finish(); } } recreate(); } - /** - * Generates a name for the server. - * @return The server name, consisting of the build model + a random string - */ - // TODO Define better name system? - private String generateName(int appendixLength){ - String AB = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"; - SecureRandom rnd = new SecureRandom(); - - StringBuilder sb = new StringBuilder(appendixLength); - for (int i = 0; i < appendixLength; i++) { - sb.append(AB.charAt(rnd.nextInt(AB.length()))); - } - - String name = Build.MODEL + "_" + sb.toString(); - Log.i(TAG, "Current name is: " + name); - return name; - } - } diff --git a/server/src/main/java/com/amos/server/ConnectionSetupServerActivity.java b/server/src/main/java/com/amos/server/ConnectionSetupServerActivity.java index 4efadd7c..8b0ce421 100644 --- a/server/src/main/java/com/amos/server/ConnectionSetupServerActivity.java +++ b/server/src/main/java/com/amos/server/ConnectionSetupServerActivity.java @@ -1,51 +1,40 @@ package com.amos.server; +import android.annotation.SuppressLint; import android.app.Activity; -import android.app.AlertDialog; -import android.content.DialogInterface; import android.content.Intent; -import android.os.Build; +import android.graphics.Point; import android.os.Bundle; -import android.os.Handler; import android.support.annotation.Nullable; import android.util.Log; +import android.view.MotionEvent; import android.view.View; -import android.widget.Button; import android.widget.ProgressBar; import android.widget.TextView; +import android.widget.Toast; -import com.amos.server.eventsender.EventServer; -import com.amos.server.signaling.WebServer; -import com.amos.server.webrtc.PeerWrapper; -import com.amos.server.webrtc.SetupStates; -import com.amos.shared.TouchEvent; -import com.google.android.gms.nearby.Nearby; -import com.google.android.gms.nearby.connection.ConnectionsClient; -import com.google.android.gms.nearby.connection.Payload; +import com.amos.server.eventsender.EventWriter; +import com.amos.server.nearby.ConnectCallback; +import com.amos.server.nearby.ServerConnection; import org.webrtc.SurfaceViewRenderer; -import java.util.concurrent.BlockingQueue; +import java.io.IOException; public class ConnectionSetupServerActivity extends Activity { private ProgressBar infiniteBar; private TextView progressText; + /** + * Connection singleton managing nearby connection + */ + private ServerConnection connection; + private EventWriter writer; + TextView connectionInfo; - Button threadStarter; - Thread senderRunner; - EventServer eventSender; - BlockingQueue msgQueue; - Handler uiHandler; SurfaceViewRenderer view; - private WebServer webSocketServer; - private PeerWrapper peerWrapper; - private SurfaceViewRenderer remoteRender; - - private String endpointId; - private static final String TAG = "ConnectionSetup"; @Override @@ -58,158 +47,78 @@ protected void onCreate(@Nullable Bundle savedInstanceState) { connectionInfo = findViewById(R.id.connectionInfo); connectionInfo.setVisibility(View.INVISIBLE); + connection = ServerConnection.getInstance(); + + // only correct actions will be processed Intent intent = getIntent(); - if (intent.hasExtra("endpointId")) { - try { - endpointId = intent.getStringExtra("endpointId"); - ConnectionsClient connection = Nearby.getConnectionsClient(this); - byte[] message = {0x61, 0x61, 0x61, 0x62}; - Payload payload = Payload.fromBytes(message); - connection.sendPayload(endpointId, payload); - Log.d(TAG, "Sent test payload to receiver " + endpointId); - } catch (NullPointerException error) { - Log.d(TAG, "Failed to get endpointId from intent"); - } + if ("connect".equals(intent.getAction())) { + buildConnection(intent.getStringExtra("name")); } else { - Log.d(TAG, "Intent did not specify endpoint"); + toInitialActivity(); } } - /** - * This method returns the SurfaceViewRender instance that - * the client is using for the screen capture streaming - * - * @return SurfaceViewRenderer return instance of SurfaceView component - */ - public SurfaceViewRenderer getRender() { - return remoteRender; - } - - private void initViews() { - remoteRender = findViewById(R.id.surface_remote_viewer); - } - - - private void restartApp() { - Intent i = getBaseContext().getPackageManager() - .getLaunchIntentForPackage(getBaseContext().getPackageName()); - i.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP); - startActivity(i); + private void toInitialActivity() { + Intent intent = new Intent(this, ConnectToClientActivity.class); + startActivity(intent); } /** - * This method should be use to update the TextView description state. - * It will write a description about the current state of the WebRTC stream. - * This method is going to handle all possible error states that the App could reach. - *

- * Please see {@link com.amos.server.webrtc.SetupStates} for the states list. - * - * @param state the identification number to identify correct or error states. + * Create connection to the given destination server */ - public void setStateText(int state) { - - AlertDialog.Builder builder; - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { - builder = new AlertDialog.Builder(this, android.R.style.Theme_Material_Dialog_Alert); - } else { - builder = new AlertDialog.Builder(this); - } - builder.setIcon(android.R.drawable.ic_dialog_alert) - .setCancelable(false) - .setTitle("Setup error"); - - builder.setNegativeButton("Restart app", new DialogInterface.OnClickListener() { + private void buildConnection(String name) { + setProgressText("Connecting to " + name); + connection.connectTo(name, new ConnectCallback() { @Override - public void onClick(DialogInterface dialogInterface, int i) { - restartApp(); - } - }); - - switch (state) { - - case SetupStates.PERMISSIONS_FOR_SCREENCAST_DENIED: - progressText.setVisibility(View.INVISIBLE); + public void success() { + Log.d(TAG, "Successfully connected to " + name); + toast(String.format("Successfully connected to %s", name)); infiniteBar.setVisibility(View.INVISIBLE); - builder.setMessage("Error getting permissions for screen capture"); - builder.show(); - break; - - case SetupStates.ASKING_PERMISSIONS: - progressText.setText("Asking permissions for screen capture"); - break; - - case SetupStates.SETUP_SCREEN_CONNECTION: - progressText.setText("Setup screen share connection with server"); - break; - - case SetupStates.LOCAL_DESCRIPTOR_CREATE: - progressText.setText("Local descriptor created Successfully"); - break; - - case SetupStates.REMOTE_DESCRIPTOR_CREATE: - progressText.setText("Remote descriptor created Successfully"); - break; - - case SetupStates.LOCAL_DESCRIPTOR_SETTED: - progressText.setText("Local descriptor setted Successfully"); - break; - - case SetupStates.REMOTE_DESCRIPTOR_SETTED: - progressText.setText("Remote descriptor setted Successfully"); progressText.setVisibility(View.INVISIBLE); - remoteRender.setVisibility(View.VISIBLE); - - break; - - case SetupStates.FAIL_CREATING_LOCAL_DESCRIPTOR: - - builder.setMessage("Creating local descriptor failed. Please restart the app"); - builder.show(); - progressText.setVisibility(View.INVISIBLE); - infiniteBar.setVisibility(View.INVISIBLE); - break; - - - case SetupStates.FAIL_CREATING_REMOTE_DESCRIPTOR: - - builder.setMessage("Creating remote descriptor failed. Please restart the app"); - builder.show(); - progressText.setVisibility(View.INVISIBLE); - infiniteBar.setVisibility(View.INVISIBLE); - break; - - - case SetupStates.FAIL_SETTED_LOCAL_DESCRIPTION: - - builder.setMessage("Setting local descriptor failed. Please restart the app"); - builder.show(); - progressText.setVisibility(View.INVISIBLE); - infiniteBar.setVisibility(View.INVISIBLE); - break; - - case SetupStates.FAIL_SETTED_REMOTE_DESCRIPTION: - builder.setMessage("Setting remote descriptor failed. Please restart the app"); - builder.show(); - progressText.setVisibility(View.INVISIBLE); - infiniteBar.setVisibility(View.INVISIBLE); - break; - + view.setVisibility(View.VISIBLE); + connectionInfo.setVisibility(View.VISIBLE); + transmitInputEvents(); + } - case SetupStates.FAIL_SENDING_SESSION_DESCRIPTOR: - builder.setMessage("Sending remote descriptor failed. Please restart the app"); - builder.show(); - progressText.setVisibility(View.INVISIBLE); - infiniteBar.setVisibility(View.INVISIBLE); - break; + @Override + public void failure() { + Log.d(TAG, "Failed to connect to " + name); + toast(String.format("Failed to connect to %s", name)); + toInitialActivity(); + } + }); + } - case SetupStates.ERROR_CONNECTING_SERVER: - builder.setMessage("Error connecting server. Please restart the app and make sure you are connected"); - builder.show(); - progressText.setVisibility(View.INVISIBLE); - infiniteBar.setVisibility(View.INVISIBLE); - break; + /** + * Send touch events over established connection + */ + @SuppressLint("ClickableViewAccessibility") + private void transmitInputEvents() { + Log.d(TAG, "Trying to transmit input events"); + toast("Trying to transmit input events"); + try { + writer = new EventWriter(connection.sendStream(), new Point(view.getWidth(), view.getHeight())); + } catch (IOException ignored) { } + view.setOnTouchListener((View v, MotionEvent event) -> { + Log.d(TAG, event.toString()); + if (writer != null) { + try { + writer.write(event); + } catch (IOException ignored) { + Log.d(TAG, "Failed to write touch event to EventWriter"); + } + } + return true; + }); } + private void toast(String message) { + Toast toast = Toast.makeText(this, message, Toast.LENGTH_SHORT); + toast.show(); + } + private void setProgressText(String message) { + progressText.setText(message); + } } diff --git a/server/src/main/java/com/amos/server/EventGrabDemo.java b/server/src/main/java/com/amos/server/EventGrabDemo.java deleted file mode 100644 index abc99d1b..00000000 --- a/server/src/main/java/com/amos/server/EventGrabDemo.java +++ /dev/null @@ -1,100 +0,0 @@ -package com.amos.server; - -import android.os.Bundle; -import android.support.design.widget.FloatingActionButton; -import android.support.design.widget.Snackbar; -import android.support.v7.app.AppCompatActivity; -import android.support.v7.widget.Toolbar; -import android.widget.TextView; -import android.view.View; -import android.view.MotionEvent; -import android.view.View.OnTouchListener; -import android.view.View.OnKeyListener; -import android.view.KeyEvent; -import android.widget.ScrollView; - -import java.util.Locale; - -class MockOutput { - TextView output; - - public MockOutput(TextView poutput) { - output = poutput; - } - - public void write(String msg) { - output.append(msg + "\n"); - } -} - -public class EventGrabDemo extends AppCompatActivity { - - View tracker; - MockOutput output; - ScrollView scroller; - - @Override - protected void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - setContentView(R.layout.activity_event_grab_demo); - Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar); - setSupportActionBar(toolbar); - - FloatingActionButton fab = (FloatingActionButton) findViewById(R.id.fab); - fab.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View view) { - Snackbar.make(view, "Replace with your own action", Snackbar.LENGTH_LONG) - .setAction("Action", null).show(); - } - }); - getSupportActionBar().setDisplayHomeAsUpEnabled(true); - - scroller = findViewById(R.id.scroller); - - output = new MockOutput((TextView)findViewById(R.id.debug)); - - tracker = findViewById(R.id.inputgrab); - tracker.setOnTouchListener(new OnTouchListener(){ - @Override - public boolean onTouch(View v, MotionEvent e) { - String msg; - int count = e.getPointerCount(); - int action = e.getActionMasked(); - int action_index = e.getActionIndex(); - int id; - float x, y; - for (int i = 0; i < count; i++) { - id = e.getPointerId(i); - x = e.getX(i); - y = e.getY(i); - msg = String.format(Locale.ENGLISH, "Count %d Index %d", count, i); - output.write(msg); - scroller.dispatchTouchEvent( - MotionEvent.obtain( - e.getDownTime(), e.getEventTime(), - action, - x + tracker.getHeight(), y, - e.getMetaState() - ) - ); - } - return true; - } - }); - tracker.setOnKeyListener(new OnKeyListener(){ - @Override - public boolean onKey(View v, int k, KeyEvent e) { - String msg; - int action = e.getAction(); - int keycode = e.getKeyCode(); - int meta = e.getMetaState(); - msg = String.format(Locale.ENGLISH, "Keycode: %d Action: %d Meta: %d", keycode, action, meta); - output.write(msg); - return true; - } - }); - - } - -} diff --git a/server/src/main/java/com/amos/server/EventSenderDemo.java b/server/src/main/java/com/amos/server/EventSenderDemo.java deleted file mode 100644 index 6e01830a..00000000 --- a/server/src/main/java/com/amos/server/EventSenderDemo.java +++ /dev/null @@ -1,84 +0,0 @@ -package com.amos.server; - -import android.Manifest; -import android.content.Context; -import android.content.IntentFilter; -import android.content.pm.PackageManager; -import android.net.wifi.p2p.WifiP2pManager; -import android.os.Build; -import android.os.Bundle; -import android.support.v7.app.AppCompatActivity; -import android.view.View; -import android.widget.Toast; - -import com.amos.server.eventsender.EventServer; -import com.amos.shared.TouchEvent; - -import java.util.concurrent.BlockingQueue; -import java.util.concurrent.LinkedBlockingQueue; - - -public class EventSenderDemo extends AppCompatActivity { - View base; - BlockingQueue mq; - private final IntentFilter intentFilter = new IntentFilter(); - private static final int COARSE_LOCATION = 1001; - - protected void createP2P(Context context) { - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M && checkSelfPermission(Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) { - Toast.makeText(this, "Requesting permission for peers", Toast.LENGTH_SHORT).show(); - requestPermissions(new String[]{Manifest.permission.ACCESS_COARSE_LOCATION}, COARSE_LOCATION); - } - // Indicates a change in the Wi-Fi P2P status. - intentFilter.addAction(WifiP2pManager.WIFI_P2P_STATE_CHANGED_ACTION); - // Indicates a change in the list of available peers. - intentFilter.addAction(WifiP2pManager.WIFI_P2P_PEERS_CHANGED_ACTION); - // Indicates the state of Wi-Fi P2P connectivity has changed. - intentFilter.addAction(WifiP2pManager.WIFI_P2P_CONNECTION_CHANGED_ACTION); - // Indicates this device's details have changed. - intentFilter.addAction(WifiP2pManager.WIFI_P2P_THIS_DEVICE_CHANGED_ACTION); - WifiP2pManager mManager = (WifiP2pManager) getSystemService(Context.WIFI_P2P_SERVICE); - WifiP2pManager.Channel mChannel = mManager.initialize(this, getMainLooper(), null); - //Making the smartphone in discovery mode for other peers - mManager.discoverPeers(mChannel, new WifiP2pManager.ActionListener() { - @Override - public void onSuccess() { - Toast.makeText(context, "Listening to Peers", Toast.LENGTH_SHORT).show(); - } - - @Override - public void onFailure(int i) { - Toast.makeText(context, "Error listening to Peers", Toast.LENGTH_SHORT).show(); - } - }); - - } - - @Override - protected void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - setContentView(R.layout.activity_event_sender_demo); - base = findViewById(R.id.senderlayout); - mq = new LinkedBlockingQueue<>(); - createP2P(this); - } - - @Override - protected void onStart() { - super.onStart(); - new Thread(new EventServer(mq)).start(); - base.setOnTouchListener( - (v, event) -> { - event.setLocation(event.getX() / base.getWidth(), event.getY() / base.getHeight()); - TouchEvent te = new TouchEvent(event.getX(), event.getY(), event.getAction(), event.getDownTime()); - mq.add(te); - return true; - } - ); - } - - @Override - protected void onStop() { - super.onStop(); - } -} diff --git a/server/src/main/java/com/amos/server/MainActivity.java b/server/src/main/java/com/amos/server/MainActivity.java deleted file mode 100644 index 2df3b0be..00000000 --- a/server/src/main/java/com/amos/server/MainActivity.java +++ /dev/null @@ -1,124 +0,0 @@ -package com.amos.server; - -import android.app.Activity; -import android.content.Intent; -import android.os.Bundle; -import android.os.Handler; -import android.os.Looper; -import android.os.Message; -import android.view.Menu; -import android.view.MenuInflater; -import android.view.MenuItem; -import android.view.MotionEvent; -import android.view.View; -import android.widget.Button; -import android.widget.TextView; - -import com.amos.server.eventsender.EventServer; -import com.amos.server.signaling.Emitter; -import com.amos.server.signaling.WebServer; -import com.amos.server.webrtc.IPeer; -import com.amos.server.webrtc.PeerWrapper; -import com.amos.shared.TouchEvent; - -import org.webrtc.PeerConnection; -import org.webrtc.SurfaceViewRenderer; - -import java.util.concurrent.BlockingQueue; -import java.util.concurrent.LinkedBlockingQueue; - -public class MainActivity extends Activity { - TextView connectionInfo; - Button threadStarter; - Thread senderRunner; - EventServer eventSender; - BlockingQueue msgQueue; - Handler uiHandler; - SurfaceViewRenderer view; - - private PeerConnection localConnection; - private WebServer webSocketServer; - private PeerWrapper peerWrapper; - private Button buttonInit; - private SurfaceViewRenderer remoteRender; - - @Override - protected void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - setContentView(R.layout.activity_main); - connectionInfo = findViewById(R.id.connectionInfo); - connectionInfo.setVisibility(View.INVISIBLE); - view = findViewById(R.id.surface_remote_viewer); - - // create touch listener components - msgQueue = new LinkedBlockingQueue<>(); - uiHandler = new Handler(Looper.getMainLooper()) { - @Override - public void handleMessage(Message msg) { - super.handleMessage(msg); - connectionInfo.setText((String) msg.obj); - } - }; - eventSender = new EventServer(msgQueue, uiHandler); - threadStarter = findViewById(R.id.threadStarter); - threadStarter.setVisibility(View.INVISIBLE); - - //init WebRTC Signaling server - this.initViews(); - this.peerWrapper = new PeerWrapper(this); - this.webSocketServer = new WebServer((IPeer) this.peerWrapper); - this.peerWrapper.setEmitter((Emitter) this.webSocketServer); - this.webSocketServer.start(); - - senderRunner = new Thread(eventSender); - senderRunner.start(); - view.setOnTouchListener( - (View v, MotionEvent e) -> { - e.setLocation(e.getX() / view.getWidth(), e.getY() / view.getHeight()); - TouchEvent te = new TouchEvent(e.getX(), e.getY(), e.getAction(), e.getDownTime()); - msgQueue.add(te); - return true; - } - ); - } - - public SurfaceViewRenderer getRender() { - return remoteRender; - } - - private void initViews() { - remoteRender = findViewById(R.id.surface_remote_viewer); - } - - @Override - public boolean onCreateOptionsMenu(Menu menu) { - MenuInflater inflater = getMenuInflater(); - inflater.inflate(R.menu.main_menu, menu); - return true; - } - - @Override - public boolean onOptionsItemSelected(MenuItem item) { - Intent intent; - switch (item.getItemId()) { - case R.id.webrtc_server_activity: - intent = new Intent(this, WebRTCServerActivity.class); - break; - case R.id.event_grab_activity: - intent = new Intent(MainActivity.this, EventGrabDemo.class); - break; - case R.id.event_sender_activity: - intent = new Intent(MainActivity.this, EventSenderDemo.class); - break; - case R.id.build_info_activity: - intent = new Intent(this, BuildInfoActivity.class); - break; - default: - return super.onOptionsItemSelected(item); - } - - startActivity(intent); - return super.onOptionsItemSelected(item); - } - -} diff --git a/server/src/main/java/com/amos/server/eventsender/EventServer.java b/server/src/main/java/com/amos/server/eventsender/EventServer.java deleted file mode 100644 index af7e03cc..00000000 --- a/server/src/main/java/com/amos/server/eventsender/EventServer.java +++ /dev/null @@ -1,152 +0,0 @@ -package com.amos.server.eventsender; - -import android.os.Handler; -import android.os.Message; -import android.os.SystemClock; -import android.util.Log; -import android.view.MotionEvent; - -import com.amos.server.signaling.SocketServer; -import com.amos.shared.TouchEvent; - -import java.io.IOException; -import java.util.concurrent.BlockingQueue; - -/** - * Pushes MotionEvents to EventWriter writing to a StreamSocket server. - * - * This is meant to be run in an independent thread in order to run networking - * components in the main thread. - * - * Events will be processed from the BlockingQueue, which can be filled from another thread. - */ -public class EventServer implements Runnable{ - SocketServer server; - EventWriter writer; - Handler uiHandler; - - BlockingQueue queue; - Boolean accepting = true; - - /** - * Create EventServer with a given input queue. - * @param mq - */ - public EventServer(BlockingQueue mq) { - queue = mq; - } - - /** - * Create EventServer with given input queua as well as UI handler to pass - * back messages to the UI thread. - * @param mq - * @param ui - */ - public EventServer(BlockingQueue mq, Handler ui) { - queue = mq; - uiHandler = ui; - } - - /** - * Accept a connection and send back one single event. - * This is meant for debugging purposes. - */ - public void accept() { - if (server == null) { - Log.d("EventServer", "Server is null."); - return; - } - Log.d("EventServer", "Waiting for connection"); - try { - writer = new EventWriter(server.getStream()); - Log.d("EventServer", "Accepted connection"); - long time = SystemClock.uptimeMillis(); - MotionEvent e = MotionEvent.obtain(time, time, MotionEvent.ACTION_DOWN, 0, 0, 1.0f, 1.0f, 0, 1.0f, 1.0f, 0, 0); - writer.write(e); - Log.d("EventServer", "Sent motion event"); - writer.close(); - } catch (IOException e) { - } - } - - /** - * Close server. - */ - public void close() { - try { - if (server != null) { - server.close(); - server = null; - } - } catch (IOException e) { - Log.d("EventServer", "Error closing writer or server."); - } - } - - /** - * Accept connection and send messages from queue. - * - * Connection will be kept alive, even if no items are in the input queue. - */ - public void acceptQueue() { - if (server == null) { - Log.d("EventServer", "Server is null."); - return; - } - while (accepting) { - try { - Log.d("EventServer", "Waiting for connection"); - writer = new EventWriter(server.getStream()); - Log.d("EventServer", "Accepted connection"); - while (true) { - try { - TouchEvent e = queue.take(); - if (e != null) { - writer.write(e); - } - } catch (IOException e) { - Log.d("EventServer", "IO Except"); - break; - } catch (InterruptedException e) { - Log.d("EventServer", "Interrupted"); - break; - } - } - writer.close(); - } catch (IOException e) { - Log.d("EventServer", "Waiting for connections interrupted"); - break; - } - } - } - - /** - * Send a message to the thread on the other side of the handler. - * @param msg - */ - private void sendMessage(String msg) { - if (uiHandler != null) { - Message m = uiHandler.obtainMessage(0, msg); - m.sendToTarget(); - } - } - - /** - * Run the SocketServer and wait for connections. - */ - @Override - public void run() { - sendMessage("Starting server"); - try { - server = new SocketServer(); - Log.d("EventServer", "Thread started"); - sendMessage("Accepting connections"); - acceptQueue(); - sendMessage("Closing server"); - server.close(); - sendMessage("Server closed. Restart application to initiate new connection."); - } catch (IOException e) { - } - } -} - diff --git a/server/src/main/java/com/amos/server/eventsender/EventWriter.java b/server/src/main/java/com/amos/server/eventsender/EventWriter.java index 29e17fdd..1942931f 100644 --- a/server/src/main/java/com/amos/server/eventsender/EventWriter.java +++ b/server/src/main/java/com/amos/server/eventsender/EventWriter.java @@ -1,35 +1,38 @@ package com.amos.server.eventsender; +import android.graphics.Point; +import android.view.MotionEvent; + import com.amos.shared.TouchEvent; import java.io.IOException; -import java.io.OutputStream; import java.io.ObjectOutputStream; -import android.view.MotionEvent; -import android.util.Log; +import java.io.OutputStream; public class EventWriter { - private OutputStream ostream; + private OutputStream outputStream; private ObjectOutputStream output; + private Point screenSize; - public EventWriter(OutputStream os) throws IOException { - ostream = os; - output = new ObjectOutputStream(ostream); + public EventWriter(OutputStream os, Point screen) throws IOException { + outputStream = os; + screenSize = screen; + output = new ObjectOutputStream(outputStream); } public void write(MotionEvent e) throws IOException { - TouchEvent te = new TouchEvent(e.getX(), e.getY(), e.getAction(), e.getDownTime()); + TouchEvent te = new TouchEvent(e, screenSize); write(te); } - public void write(TouchEvent e) throws IOException { + void write(TouchEvent e) throws IOException { output.writeObject(e); output.flush(); } public void close() throws IOException { output.close(); - ostream.close(); + outputStream.close(); } } diff --git a/server/src/main/java/com/amos/server/nearby/ConnectCallback.java b/server/src/main/java/com/amos/server/nearby/ConnectCallback.java new file mode 100644 index 00000000..aaffec83 --- /dev/null +++ b/server/src/main/java/com/amos/server/nearby/ConnectCallback.java @@ -0,0 +1,6 @@ +package com.amos.server.nearby; + +public interface ConnectCallback { + void success(); + void failure(); +} diff --git a/server/src/main/java/com/amos/server/nearby/ServerConnection.java b/server/src/main/java/com/amos/server/nearby/ServerConnection.java new file mode 100644 index 00000000..09d53dc8 --- /dev/null +++ b/server/src/main/java/com/amos/server/nearby/ServerConnection.java @@ -0,0 +1,329 @@ +package com.amos.server.nearby; + +import android.content.Context; +import android.os.Build; +import android.support.annotation.NonNull; +import android.util.Log; + +import com.google.android.gms.nearby.Nearby; +import com.google.android.gms.nearby.connection.ConnectionInfo; +import com.google.android.gms.nearby.connection.ConnectionLifecycleCallback; +import com.google.android.gms.nearby.connection.ConnectionResolution; +import com.google.android.gms.nearby.connection.ConnectionsClient; +import com.google.android.gms.nearby.connection.ConnectionsStatusCodes; +import com.google.android.gms.nearby.connection.DiscoveredEndpointInfo; +import com.google.android.gms.nearby.connection.DiscoveryOptions; +import com.google.android.gms.nearby.connection.EndpointDiscoveryCallback; +import com.google.android.gms.nearby.connection.Payload; +import com.google.android.gms.nearby.connection.PayloadCallback; +import com.google.android.gms.nearby.connection.PayloadTransferUpdate; +import com.google.android.gms.nearby.connection.Strategy; + +import java.io.IOException; +import java.io.PipedInputStream; +import java.io.PipedOutputStream; +import java.security.SecureRandom; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; + +/** + * Singleton managing Android nearby connection on the server side + *

+ * The server needs to send input events to the client and correctly receive the recorded screen. + */ +public class ServerConnection { + + private static final ServerConnection ourInstance = new ServerConnection(); + + /** + * 1-to-1 since a device will be connected to only one other device at most. + */ + private static final Strategy STRATEGY = Strategy.P2P_POINT_TO_POINT; + + private final String serverName = generateName(); + + private String clientID; + + /** + * List of all discovered servers by name, continuously updated. + */ + private List clients = new ArrayList<>(); + + /** + * Maps server names to their nearby connection IDs. + */ + private HashMap clientNamesToIDs = new HashMap<>(); + + /** + * Maps server IDs to their nearby connection names. + */ + private HashMap clientIDsToNames = new HashMap<>(); + + /** + * Tag for logging purposes. + */ + private static final String TAG = "NearbyServer"; + + /** + * Connection manager for the connection to FlyInn clients. + */ + private ConnectionsClient connectionsClient; + + public static ServerConnection getInstance() { + return ourInstance; + } + + /** + * Create a new server connection. + */ + private ServerConnection() { + // All real work is in the init! + } + + /** + * Bind application context to the singleton. + * + * @param ctx Application context should be passed to ensure survival between different activities. + */ + public void init(Context ctx) { + connectionsClient = Nearby.getConnectionsClient(ctx); + } + + /** + * Clears all servers map data as well as serverName/serverID and starts discovery + */ + public void discover() { + if (connectionsClient == null) { + Log.e(TAG, "connectionsClient is null, cannot discover."); + return; + } + resetDiscovery(); + + DiscoveryOptions discoveryOptions = + new DiscoveryOptions.Builder().setStrategy(STRATEGY).build(); + + connectionsClient.startDiscovery("com.amos.server", endpointDiscoveryCallback, + discoveryOptions) + .addOnSuccessListener((Void unused) -> { + // started searching for servers successfully + Log.i(TAG, "Discovering connections on " + serverName); + }) + .addOnFailureListener((Exception e) -> { + // unable to start discovery + Log.e(TAG, e.toString()); + Log.e(TAG, "Unable to start discovery on " + serverName); + }); + } + + public List getClients() { + return clients; + } + + public String getClientID() { + return clientID; + } + + /** + * Connect to nearby service with client name ending with our required code. + * + * @param code Suffix of connection target + * @param callback Callbacks on connection success and failure + */ + public void connectTo(String code, ConnectCallback callback) { + if (connectionsClient == null) { + Log.e(TAG, "connectionsClient is null, cannot discover."); + return; + } + String searchedClientName = null; + for (String clientName : clients) { + if (clientName.endsWith(code)) { + searchedClientName = clientName; + break; + } + } + + String endpoint = clientNamesToIDs.get(searchedClientName); + if (endpoint != null && searchedClientName != null) { + clientID = endpoint; + // callback success will be called in the subsequent function + connectionsClient.requestConnection(searchedClientName, endpoint, buildConnectionLifecycleCallback(callback)); + } else { + callback.failure(); + } + + } + + public void abort() { + resetDiscovery(); + resetClientData(); + } + + public PipedOutputStream sendStream() throws IOException { + if (connectionsClient == null) { + Log.e(TAG, "connectionsClient is null, cannot create stream."); + throw new IOException("connectionsClient is null, cannot create stream."); + } + PipedInputStream stream = new PipedInputStream(); + PipedOutputStream data = new PipedOutputStream(stream); + Payload payload = Payload.fromStream(stream); + connectionsClient.sendPayload(clientID, payload); + Log.d(TAG, "Sent test payload to receiver " + clientID); + return data; + } + + /** + * Obtain data from clientID/serverName and data transfer information via this handle. + */ + private final PayloadCallback payloadCallback = + new PayloadCallback() { + @Override + public void onPayloadReceived(@NonNull String endpointId, @NonNull Payload payload) { + Log.d(TAG, "Payload received from " + endpointId); + Log.d(TAG, payload.toString()); + } + + @Override + public void onPayloadTransferUpdate(@NonNull String endpointId, @NonNull PayloadTransferUpdate update) { + Log.d(TAG, "Payload transfer update from " + endpointId); + Log.d(TAG, update.toString()); + } + }; + + /** + * Handling of discovered endpoints (servers). Adds new endpoints to servers data maps/list, + * and removes lost endpoints. + */ + private final EndpointDiscoveryCallback endpointDiscoveryCallback = + new EndpointDiscoveryCallback() { + @Override + public void onEndpointFound(@NonNull String endpointId, @NonNull DiscoveredEndpointInfo info) { + // discovered a server, add to data maps + String endpointName = info.getEndpointName(); + + if (!(clientIDsToNames.containsKey(endpointId) + || clientNamesToIDs.containsKey(endpointName))) { + clients.add(endpointName); + clientNamesToIDs.put(endpointName, endpointId); + clientIDsToNames.put(endpointId, endpointName); + Log.i(TAG, serverName + " discovered endpoint " + endpointId + " with name " + endpointName); + + } else { + // this should not happen + while (true) { + if (!clients.remove(endpointName)) break; + } + clients.add(endpointName); + clientIDsToNames.put(endpointId, endpointName); + clientNamesToIDs.put(endpointName, endpointId); + Log.i(TAG, serverName + " rediscovered endpoint " + endpointId + " with name " + endpointName); + } + } + + @Override + public void onEndpointLost(@NonNull String endpointId) { + // previously discovered server is no longer reachable, remove from data maps + String lostEndpointName = clientIDsToNames.get(endpointId); + clients.remove(lostEndpointName); + clientIDsToNames.remove(endpointId); + clientNamesToIDs.remove(lostEndpointName); + Log.i(TAG, serverName + " lost discovered endpoint " + endpointId); + } + }; + + private ConnectionLifecycleCallback buildConnectionLifecycleCallback(ConnectCallback callback) { + return new ConnectionLifecycleCallback() { + @Override + public void onConnectionInitiated(@NonNull String endpointId, @NonNull ConnectionInfo connectionInfo) { + Log.i(TAG, "Connection initiated to " + endpointId); + + if (endpointId.equals(clientID)) { + connectionsClient.acceptConnection(endpointId, payloadCallback); + } else { + // initiated connection is not with server selected by user + connectionsClient.rejectConnection(endpointId); + Log.i(TAG, "Connection rejected to non-selected server " + + endpointId); + } + } + + @Override + public void onConnectionResult(@NonNull String endpointId, @NonNull ConnectionResolution result) { + switch (result.getStatus().getStatusCode()) { + case ConnectionsStatusCodes.STATUS_OK: + // successful connection with server + Log.i(TAG, "Connected with " + endpointId); + resetDiscovery(); + callback.success(); + break; + case ConnectionsStatusCodes.STATUS_CONNECTION_REJECTED: + // connection was rejected by one side (or both) + Log.i(TAG, "Connection rejected with " + endpointId); + clientID = null; + callback.failure(); + break; + case ConnectionsStatusCodes.STATUS_ERROR: + // connection was lost + Log.w(TAG, "Connection lost: " + endpointId); + clientID = null; + callback.failure(); + break; + default: + // unknown status code. we shouldn't be here + Log.e(TAG, "Unknown error when attempting to connect with " + + endpointId); + clientID = null; + callback.failure(); + break; + } + } + + @Override + public void onDisconnected(@NonNull String endpointId) { + // disconnected from server + Log.i(TAG, "Disconnected from " + endpointId); + resetClientData(); + } + }; + } + + /** + * Generates a name for the server. + *

+ * TODO: Create a better name for the server + * + * @return The server name, consisting of the build model + a random string + */ + private String generateName() { + String AB = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"; + SecureRandom rnd = new SecureRandom(); + + StringBuilder sb = new StringBuilder(5); + for (int i = 0; i < 5; i++) { + sb.append(AB.charAt(rnd.nextInt(AB.length()))); + } + + String name = Build.MODEL + "_" + sb.toString(); + Log.i(TAG, "Current name is: " + name); + return name; + } + + /** + * Clears serverName/serverID and all server data maps as well as the servers list + */ + private void resetClientData() { + clientID = null; + } + + /** + * Handle established connection with app. + *

+ * Clears servers data maps, stops discovery of new servers and adds close connection button + */ + private void resetDiscovery() { + connectionsClient.stopDiscovery(); + clients.clear(); + clientNamesToIDs.clear(); + clientIDsToNames.clear(); + } +} diff --git a/server/src/main/java/com/amos/server/signaling/Emitter.java b/server/src/main/java/com/amos/server/signaling/Emitter.java index 60a162ad..397f3b8f 100644 --- a/server/src/main/java/com/amos/server/signaling/Emitter.java +++ b/server/src/main/java/com/amos/server/signaling/Emitter.java @@ -6,5 +6,6 @@ public interface Emitter { public void shareSessionDescription(SessionDescription session); + public void shareIceCandidate(IceCandidate candidate); } diff --git a/server/src/main/java/com/amos/server/signaling/SocketServer.java b/server/src/main/java/com/amos/server/signaling/SocketServer.java deleted file mode 100644 index 4de077f8..00000000 --- a/server/src/main/java/com/amos/server/signaling/SocketServer.java +++ /dev/null @@ -1,28 +0,0 @@ -package com.amos.server.signaling; - -import java.io.IOException; -import java.net.ServerSocket; -import java.net.Socket; -import java.io.OutputStream; - -public class SocketServer { - - private ServerSocket socket; - private Socket client; - - public SocketServer() throws IOException { - socket = new ServerSocket(1337); - } - - public OutputStream getStream() throws IOException { - client = socket.accept(); - return client.getOutputStream(); - } - - public void close() throws IOException { - if (client != null) { - client.close(); - } - socket.close(); - } -} diff --git a/server/src/main/java/com/amos/server/signaling/WebServer.java b/server/src/main/java/com/amos/server/signaling/WebServer.java index c5c55fd3..682af280 100644 --- a/server/src/main/java/com/amos/server/signaling/WebServer.java +++ b/server/src/main/java/com/amos/server/signaling/WebServer.java @@ -7,7 +7,6 @@ import org.java_websocket.WebSocket; import org.java_websocket.handshake.ClientHandshake; import org.java_websocket.server.WebSocketServer; -import org.json.JSONException; import org.json.JSONObject; import org.webrtc.IceCandidate; import org.webrtc.SessionDescription; @@ -18,9 +17,8 @@ public class WebServer extends WebSocketServer implements Emitter { private IPeer peer; - public WebServer(IPeer peer){ - - super( new InetSocketAddress( 8080 )); + public WebServer(IPeer peer) { + super(new InetSocketAddress(8080)); this.peer = peer; } @@ -36,30 +34,26 @@ public void onClose(WebSocket conn, int code, String reason, boolean remote) { @Override public void onMessage(WebSocket conn, String message) { - Log.d("WebServer","I received this : " + message); - try{ + Log.d("WebServer", "I received this : " + message); + try { JSONObject receivedObject = new JSONObject(message); String typeMessage = receivedObject.getString("type-message"); - if(typeMessage.equals("offerClient")) - { + if (typeMessage.equals("offerClient")) { String sdp = receivedObject.getString("sdp"); - SessionDescription offerSessionDescriptionClient = new SessionDescription(SessionDescription.Type.OFFER,sdp); + SessionDescription offerSessionDescriptionClient = new SessionDescription(SessionDescription.Type.OFFER, sdp); this.peer.setRemoteDescriptorPeer(offerSessionDescriptionClient); - } - else if(typeMessage.equals("candidate-client")) { - Log.d("WebServer","Getting candidate from client : " + receivedObject.toString()); + } else if (typeMessage.equals("candidate-client")) { + Log.d("WebServer", "Getting candidate from client : " + receivedObject.toString()); String id = receivedObject.getString("id"); int label = receivedObject.getInt("label"); String candidate = receivedObject.getString("candidate"); - IceCandidate newCandidate = new IceCandidate(id,label,candidate); + IceCandidate newCandidate = new IceCandidate(id, label, candidate); this.peer.setRemoteIceCandidate(newCandidate); } - } - catch (Exception e) - { + } catch (Exception e) { e.printStackTrace(); } @@ -76,16 +70,15 @@ public void onStart() { } - public JSONObject serializeDescription(SessionDescription session){ - try{ + public JSONObject serializeDescription(SessionDescription session) { + try { JSONObject sessionObject = new JSONObject(); - sessionObject.put("type-message","answerServer"); + sessionObject.put("type-message", "answerServer"); sessionObject.put("type", session.type.canonicalForm()); sessionObject.put("sdp", session.description); - Log.d("WebServer","simulating the description message sending answer : " + sessionObject); + Log.d("WebServer", "simulating the description message sending answer : " + sessionObject); return sessionObject; - }catch (Exception e) - { + } catch (Exception e) { e.printStackTrace(); } @@ -94,24 +87,23 @@ public JSONObject serializeDescription(SessionDescription session){ @Override public void shareSessionDescription(SessionDescription session) { - Log.d("WebServer","Sending session answer : " + session); + Log.d("WebServer", "Sending session answer : " + session); JSONObject sessionObject = this.serializeDescription(session); - Log.d("WebServer","simulating the description message sending answer : " + sessionObject); + Log.d("WebServer", "simulating the description message sending answer : " + sessionObject); this.broadcast(sessionObject.toString()); } - public JSONObject serializeIceCandidate(IceCandidate candidate){ - try{ + public JSONObject serializeIceCandidate(IceCandidate candidate) { + try { JSONObject jsonIceCandidate = new JSONObject(); - jsonIceCandidate.put("type-message","candidate-server"); + jsonIceCandidate.put("type-message", "candidate-server"); jsonIceCandidate.put("type", "candidate"); jsonIceCandidate.put("label", candidate.sdpMLineIndex); jsonIceCandidate.put("id", candidate.sdpMid); jsonIceCandidate.put("candidate", candidate.sdp); return jsonIceCandidate; - }catch(Exception e) - { + } catch (Exception e) { e.printStackTrace(); } @@ -120,11 +112,11 @@ public JSONObject serializeIceCandidate(IceCandidate candidate){ @Override public void shareIceCandidate(IceCandidate candidate) { - Log.d("WebServer","I am sharing this candidate : " + candidate); - Log.d("WebServer","Sending icecandidate! -- " + candidate); + Log.d("WebServer", "I am sharing this candidate : " + candidate); + Log.d("WebServer", "Sending icecandidate! -- " + candidate); JSONObject jsonIceCandidate = this.serializeIceCandidate(candidate); - Log.d("WebServer","simulating the icecandidate message sending : " + jsonIceCandidate); + Log.d("WebServer", "simulating the icecandidate message sending : " + jsonIceCandidate); this.broadcast(jsonIceCandidate.toString()); - } } +} diff --git a/server/src/main/java/com/amos/server/webrtc/PeerWrapper.java b/server/src/main/java/com/amos/server/webrtc/PeerWrapper.java index 44f94829..b31bd6d6 100644 --- a/server/src/main/java/com/amos/server/webrtc/PeerWrapper.java +++ b/server/src/main/java/com/amos/server/webrtc/PeerWrapper.java @@ -1,17 +1,12 @@ package com.amos.server.webrtc; import android.app.Activity; -import android.app.Application; import android.content.Context; import android.util.Log; -import android.view.View; import com.amos.server.ConnectionSetupServerActivity; -import com.amos.server.MainActivity; -import com.amos.server.WebRTCServerActivity; import com.amos.server.signaling.Emitter; -import org.webrtc.Camera1Enumerator; import org.webrtc.DefaultVideoDecoderFactory; import org.webrtc.DefaultVideoEncoderFactory; import org.webrtc.EglBase; @@ -21,7 +16,6 @@ import org.webrtc.PeerConnection; import org.webrtc.PeerConnectionFactory; import org.webrtc.SessionDescription; -import org.webrtc.VideoCapturer; import org.webrtc.VideoTrack; import java.util.ArrayList; @@ -54,8 +48,8 @@ public PeerWrapper(Activity app) { } private void initComponents(){ - this.activity.getRender().setZOrderMediaOverlay(true); - this.activity.getRender().init(this.rootEglBase.getEglBaseContext(),null); + // this.activity.getRender().setZOrderMediaOverlay(true); + // this.activity.getRender().init(this.rootEglBase.getEglBaseContext(),null); } public void setEmitter(Emitter emitter){ @@ -116,8 +110,8 @@ public void setRemoteStream(MediaStream stream) { this.activity.runOnUiThread(new Runnable() { @Override public void run() { - activity.getRender().setVisibility(View.VISIBLE); - trackRemoteCamera.addSink(activity.getRender()); + // activity.getRender().setVisibility(View.VISIBLE); + // trackRemoteCamera.addSink(activity.getRender()); } }); } diff --git a/server/src/main/java/com/amos/server/webrtc/SdpObserver.java b/server/src/main/java/com/amos/server/webrtc/SdpObserver.java index e57d64f0..0283fa36 100644 --- a/server/src/main/java/com/amos/server/webrtc/SdpObserver.java +++ b/server/src/main/java/com/amos/server/webrtc/SdpObserver.java @@ -4,11 +4,8 @@ import android.util.Log; import com.amos.server.ConnectionSetupServerActivity; -import com.amos.server.webrtc.SetupStates; import org.webrtc.SessionDescription; - -import java.util.Set; /** *

SdpObserver Class

* @@ -30,7 +27,7 @@ public class SdpObserver implements org.webrtc.SdpObserver { * * @param nameObserver the observer name to recognize the ObserverObject in the logs * @param activity the activity to access the TextView - * @param type the type of the Observer. Remote or Local. Please look at the constants at {@link com.amos.flyinn.webrtc.SdpObserver } + * @param type the type of the Observer. Remote or Local. Please look at the constants at */ public SdpObserver(String nameObserver, Activity activity,int type) { @@ -61,7 +58,7 @@ public void onCreateSuccess(SessionDescription sessionDescription) { activity.runOnUiThread(new Runnable() { @Override public void run() { - activity.setStateText(SetupStates.LOCAL_DESCRIPTOR_CREATE); + // activity.setStateText(SetupStates.LOCAL_DESCRIPTOR_CREATE); } }); } @@ -71,7 +68,7 @@ public void run() { activity.runOnUiThread(new Runnable() { @Override public void run() { - activity.setStateText(SetupStates.REMOTE_DESCRIPTOR_CREATE); + // activity.setStateText(SetupStates.REMOTE_DESCRIPTOR_CREATE); } }); } @@ -94,7 +91,7 @@ public void onSetSuccess() { activity.runOnUiThread(new Runnable() { @Override public void run() { - activity.setStateText(SetupStates.LOCAL_DESCRIPTOR_SETTED); + // activity.setStateText(SetupStates.LOCAL_DESCRIPTOR_SETTED); } }); } @@ -104,7 +101,7 @@ public void run() { activity.runOnUiThread(new Runnable() { @Override public void run() { - activity.setStateText(SetupStates.REMOTE_DESCRIPTOR_SETTED); + // activity.setStateText(SetupStates.REMOTE_DESCRIPTOR_SETTED); } }); } @@ -126,7 +123,7 @@ public void onCreateFailure(String s) { activity.runOnUiThread(new Runnable() { @Override public void run() { - activity.setStateText(SetupStates.FAIL_CREATING_LOCAL_DESCRIPTOR); + // activity.setStateText(SetupStates.FAIL_CREATING_LOCAL_DESCRIPTOR); } }); } @@ -136,7 +133,7 @@ public void run() { activity.runOnUiThread(new Runnable() { @Override public void run() { - activity.setStateText(SetupStates.FAIL_CREATING_REMOTE_DESCRIPTOR); + // activity.setStateText(SetupStates.FAIL_CREATING_REMOTE_DESCRIPTOR); } }); } @@ -158,7 +155,7 @@ public void onSetFailure(String s) { activity.runOnUiThread(new Runnable() { @Override public void run() { - activity.setStateText(SetupStates.FAIL_SETTED_LOCAL_DESCRIPTION); + // activity.setStateText(SetupStates.FAIL_SETTED_LOCAL_DESCRIPTION); } }); } @@ -168,7 +165,7 @@ public void run() { activity.runOnUiThread(new Runnable() { @Override public void run() { - activity.setStateText(SetupStates.FAIL_SETTED_REMOTE_DESCRIPTION); + // activity.setStateText(SetupStates.FAIL_SETTED_REMOTE_DESCRIPTION); } }); } diff --git a/server/src/main/java/com/amos/server/wifibroadcaster/WifiBroadcasterSingleton.java b/server/src/main/java/com/amos/server/wifibroadcaster/WifiBroadcasterSingleton.java deleted file mode 100644 index 85d39b9e..00000000 --- a/server/src/main/java/com/amos/server/wifibroadcaster/WifiBroadcasterSingleton.java +++ /dev/null @@ -1,44 +0,0 @@ -package com.amos.server.wifibroadcaster; - -import android.app.Activity; -import android.net.wifi.p2p.WifiP2pManager; - -/** - * Manage WifiServiceManager instances for the whole application. - * - * Only one connection needs to be handled at any time, but the object itself can change depending - * on disconnects and other operations. This wrapper class handles global access to the WifiServiceManager object. - */ -public class WifiBroadcasterSingleton { - private static final WifiBroadcasterSingleton ourInstance = new WifiBroadcasterSingleton(); - private WifiServiceManager s; - - /** - * Get current WifiBroadcaster. - * - * This follows a standard singleton pattern for java. Other objects have to reference to this - * class via a getter, thus avoiding creating additional instances of this class across the application. - * @return - */ - public static WifiBroadcasterSingleton getInstance() { - return ourInstance; - } - - /** - * Get the current WifiBroadcaster - * @return - */ - public WifiServiceManager getBroadcaster() { - return this.s; - } - - /** - * Create a new WifiServiceManager using given P2P objects. - * @param manager - * @param channel - * @param activity - */ - public void setInstance(WifiP2pManager manager, WifiP2pManager.Channel channel , Activity activity) { - this.s = new WifiServiceManager(manager, channel, activity); - } -} diff --git a/server/src/main/java/com/amos/server/wifibroadcaster/WifiConnectionService.java b/server/src/main/java/com/amos/server/wifibroadcaster/WifiConnectionService.java deleted file mode 100644 index bcd23fa2..00000000 --- a/server/src/main/java/com/amos/server/wifibroadcaster/WifiConnectionService.java +++ /dev/null @@ -1,79 +0,0 @@ -package com.amos.server.wifibroadcaster; - -import android.app.Activity; -import android.content.Intent; -import android.net.wifi.p2p.WifiP2pInfo; -import android.net.wifi.p2p.WifiP2pManager; -import android.util.Log; -import android.widget.Toast; - -import com.amos.server.ConnectionSetupServerActivity; - -import java.net.InetAddress; -import java.net.NetworkInterface; -import java.net.SocketException; -import java.util.Enumeration; - -/** - * Process wifi connection information and setup further activity switch to setup connections between Event and Screen sharing processes. - */ -class WifiConnectionService implements WifiP2pManager.ConnectionInfoListener { - private Activity activity; - private WifiP2pManager.Channel mChannel; - private WifiP2pManager mManager; - - /** - * Create a new connection service. - * @param activity - * @param manager - * @param channel - */ - WifiConnectionService(Activity activity, WifiP2pManager manager, WifiP2pManager.Channel channel) { - this.activity = activity; - this.mChannel = channel; - this.mManager = manager; - } - - /** - * Display information on established connection (ie accepted invitation to P2P network) and trigger activity change. - * @param wifiP2pInfo - */ - @Override - public void onConnectionInfoAvailable(WifiP2pInfo wifiP2pInfo) { - InetAddress address = wifiP2pInfo.groupOwnerAddress; - Toast.makeText(activity, "Connected to the address : " + address.getHostAddress(), Toast.LENGTH_LONG).show(); - Toast.makeText(activity, "Closing discovery mode for peers" + address.getHostAddress(), Toast.LENGTH_LONG).show(); - mManager.stopPeerDiscovery(mChannel, new WifiP2pManager.ActionListener() { - @Override - public void onSuccess() { - Toast.makeText(activity, "Discovery mode closed Successfully", Toast.LENGTH_LONG).show(); - } - - @Override - public void onFailure(int i) { - Toast.makeText(activity, "Failed to close Discovery mode", Toast.LENGTH_LONG).show(); - } - }); - try { - Enumeration en = NetworkInterface.getNetworkInterfaces(); - while (en.hasMoreElements()) { - NetworkInterface inet = en.nextElement(); - Log.d("WifiConnectionService", inet.getInterfaceAddresses().toString()); - } - } catch (SocketException e) { - e.printStackTrace(); - } - setupNext(); - } - - /** - * Start ConnectionSetupActivity. - * - * This function is called after connection information has been made available, which is a callback - * defined in the WifiP2P library. - */ - private void setupNext(){ - Intent intent = new Intent(activity,ConnectionSetupServerActivity.class); - activity.startActivity(intent); - } -} diff --git a/server/src/main/java/com/amos/server/wifibroadcaster/WifiHijackBase.java b/server/src/main/java/com/amos/server/wifibroadcaster/WifiHijackBase.java deleted file mode 100644 index 4527db63..00000000 --- a/server/src/main/java/com/amos/server/wifibroadcaster/WifiHijackBase.java +++ /dev/null @@ -1,169 +0,0 @@ -package com.amos.server.wifibroadcaster; - -import android.Manifest; -import android.annotation.SuppressLint; -import android.content.Context; -import android.content.IntentFilter; -import android.content.pm.PackageManager; -import android.net.wifi.WifiManager; -import android.net.wifi.p2p.WifiP2pManager; -import android.os.Build; -import android.os.Bundle; -import android.support.annotation.NonNull; -import android.support.annotation.Nullable; -import android.support.v7.app.AppCompatActivity; -import android.util.Log; -import android.widget.Toast; - -import com.amos.server.R; - -import java.lang.reflect.Method; - -/** - * Set up Wifimanager and handle Intents. Calls are passed through to the WifiBroadCasterSingleton. - */ -public abstract class WifiHijackBase extends AppCompatActivity { - private final IntentFilter intentFilter = new IntentFilter(); - private WifiP2pManager.Channel mChannel; - private WifiP2pManager mManager; - private static final int COARSE_LOCATION = 1001; - - /** - * Register handled intents and get all required permissions for Wifi P2P - * @param savedInstanceState - */ - @Override - protected void onCreate(@Nullable Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M && checkSelfPermission(Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) { - Toast.makeText(this, "Requesting permission for peers", Toast.LENGTH_SHORT).show(); - requestPermissions(new String[]{Manifest.permission.ACCESS_COARSE_LOCATION}, COARSE_LOCATION); - } - Log.d("onCreate", "called"); - - // Indicates a change in the Wi-Fi P2P status. - intentFilter.addAction(WifiP2pManager.WIFI_P2P_STATE_CHANGED_ACTION); - - // Indicates a change in the list of available peers. - intentFilter.addAction(WifiP2pManager.WIFI_P2P_PEERS_CHANGED_ACTION); - - // Indicates the state of Wi-Fi P2P connectivity has changed. - intentFilter.addAction(WifiP2pManager.WIFI_P2P_CONNECTION_CHANGED_ACTION); - - // Indicates this device's details have changed. - intentFilter.addAction(WifiP2pManager.WIFI_P2P_THIS_DEVICE_CHANGED_ACTION); - - this.mManager = (WifiP2pManager) getSystemService(Context.WIFI_P2P_SERVICE); - this.mChannel = mManager.initialize(this, getMainLooper(), null); - - this.disconnect(); - } - - protected void disconnect() { - try { - @SuppressLint("WifiManagerLeak") - WifiManager wifiManager = (WifiManager) getSystemService(Context.WIFI_SERVICE); - wifiManager.setWifiEnabled(false); - Thread.sleep(100); - wifiManager.setWifiEnabled(true); - } catch (Exception e) { - } - - - - try { - Method[] methods = WifiP2pManager.class.getMethods(); - for (int i = 0; i < methods.length; i++) { - if (methods[i].getName().equals("deletePersistentGroup")) { - // Delete any persistent group - for (int netid = 0; netid < 32; netid++) { - methods[i].invoke(mManager, mChannel, netid, null); - } - } - } - } catch (Exception e) { - e.printStackTrace(); - } - } - - private void setWifiName(String name) { - Log.d("ChangeWifiName", "New name:" + name); - String fullName = getString(R.string.product_name_prefix_identifier) + name; - try { - Method method = this.mManager.getClass().getMethod("setDeviceName", new Class[]{WifiP2pManager.Channel.class, String.class, WifiP2pManager.ActionListener.class}); - method.invoke(this.mManager, this.mChannel, fullName, null); - } catch (Exception e) { - e.printStackTrace(); - } - } - - /** - * Set the correct wifi name and initiate peer search. Further actions are handled in the - * WifiBroadcasterSingleton. - * - * We change the name of our server network to the one the WifiP2P on the app is expecting. - * This way we can establish the connection from the server side without further interaction - * on the client. - * - * @param name - */ - public void changeName(String name) { - try { - unregisterReceiver(WifiBroadcasterSingleton.getInstance().getBroadcaster()); - mManager.stopPeerDiscovery(mChannel, null); - } catch (Exception e) { - e.printStackTrace(); - } - - this.mChannel = mManager.initialize(this, getMainLooper(), null); - this.setWifiName(name); - WifiBroadcasterSingleton.getInstance().setInstance(mManager, mChannel, this); - registerReceiver(WifiBroadcasterSingleton.getInstance().getBroadcaster(), this.intentFilter); - - Log.d("changeName", "Start discovering"); - this.mManager.discoverPeers(mChannel, new WifiP2pManager.ActionListener() { - @Override - public void onSuccess() { - Toast.makeText(WifiHijackBase.this, "Listening to Peers", Toast.LENGTH_SHORT).show(); - } - - @Override - public void onFailure(int i) { - Toast.makeText(WifiHijackBase.this, "Error listening to Peers", Toast.LENGTH_SHORT).show(); - } - }); - } - - /** - * Rebind to WifiBroadCasterSingleton on resume. - */ - @Override - public void onResume() { - super.onResume(); - WifiBroadcasterSingleton.getInstance().setInstance(mManager, mChannel, this); - registerReceiver(WifiBroadcasterSingleton.getInstance().getBroadcaster(), intentFilter); - } - - /** - * Do not continue to listen on program pause. - */ - @Override - public void onPause() { - super.onPause(); - unregisterReceiver(WifiBroadcasterSingleton.getInstance().getBroadcaster()); - } - - /** - * Show visual feedback if permissions for WifiP2P have been correctly granted. - * - * @param requestCode - * @param permissions - * @param grantResults - */ - @Override - public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) { - if (requestCode == COARSE_LOCATION && grantResults[0] == PackageManager.PERMISSION_GRANTED) { - Toast.makeText(this, "Permission for peers listening given", Toast.LENGTH_SHORT).show(); - } - } -} diff --git a/server/src/main/java/com/amos/server/wifibroadcaster/WifiServiceManager.java b/server/src/main/java/com/amos/server/wifibroadcaster/WifiServiceManager.java deleted file mode 100644 index 391391d1..00000000 --- a/server/src/main/java/com/amos/server/wifibroadcaster/WifiServiceManager.java +++ /dev/null @@ -1,59 +0,0 @@ -package com.amos.server.wifibroadcaster; - -import android.app.Activity; -import android.content.BroadcastReceiver; -import android.content.Context; -import android.content.Intent; -import android.net.NetworkInfo; -import android.net.wifi.p2p.WifiP2pManager; -import android.util.Log; - -/** - * Use intent broadcasts to trigger activity changes and further connection setup. - */ -class WifiServiceManager extends BroadcastReceiver { - private WifiP2pManager mManager; - private WifiP2pManager.Channel mChannel; - private WifiConnectionService connectionService; - - /** - * Create a new WifiService manager. - * - * This constructor should only be called by the broadcaster. - * @param manager - * @param channel - * @param activity - */ - public WifiServiceManager(WifiP2pManager manager, WifiP2pManager.Channel channel, Activity activity) { - this.mManager = manager; - this.mChannel = channel; - this.connectionService = new WifiConnectionService(activity, mManager, mChannel); - } - - /** - * Try to get connection information on connection setup message from Wifi P2P - * - * Further processing is handled by WifiConnectionService, which acts on the resulting connection information. - * @param context - * @param intent - */ - @Override - public void onReceive(Context context, Intent intent) { - String action = intent.getAction(); - if (WifiP2pManager.WIFI_P2P_CONNECTION_CHANGED_ACTION.equals(action)) { - if (mManager != null) { - NetworkInfo infoNet = intent.getParcelableExtra(WifiP2pManager.EXTRA_NETWORK_INFO); - if (infoNet.isConnected()) { - try { - Log.d("TestHere","test"); - mManager.requestConnectionInfo(mChannel, this.connectionService); - } catch (Exception e) { - e.printStackTrace(); - Log.d("onReceive", "requestConnectionInfo fatal error"); - } - } - } - Log.d("WifiReceiverP2P", "Connection Changed Action"); - } - } -} diff --git a/server/src/main/res/layout/activity_event_grab_demo.xml b/server/src/main/res/layout/activity_event_grab_demo.xml deleted file mode 100644 index 17e47f02..00000000 --- a/server/src/main/res/layout/activity_event_grab_demo.xml +++ /dev/null @@ -1,33 +0,0 @@ - - - - - - - - - - - - - - \ No newline at end of file diff --git a/server/src/main/res/layout/activity_event_sender_demo.xml b/server/src/main/res/layout/activity_event_sender_demo.xml deleted file mode 100644 index b1a7effb..00000000 --- a/server/src/main/res/layout/activity_event_sender_demo.xml +++ /dev/null @@ -1,10 +0,0 @@ - - - - \ No newline at end of file diff --git a/server/src/main/res/layout/activity_main.xml b/server/src/main/res/layout/activity_main.xml deleted file mode 100644 index e3ec94ac..00000000 --- a/server/src/main/res/layout/activity_main.xml +++ /dev/null @@ -1,56 +0,0 @@ - - - -