diff --git a/client/android/Notifier/app/src/main/java/com/mobilesec/client/notifier/MainActivity.java b/client/android/Notifier/app/src/main/java/com/mobilesec/client/notifier/MainActivity.java index fc7f649becb3cb2a3373cfc0351626303e3acb16..55a1cc768faedaf840d9623eddd3886097ae587d 100644 --- a/client/android/Notifier/app/src/main/java/com/mobilesec/client/notifier/MainActivity.java +++ b/client/android/Notifier/app/src/main/java/com/mobilesec/client/notifier/MainActivity.java @@ -10,29 +10,63 @@ import android.app.NotificationManager; import android.content.IntentFilter; import android.os.Build; import android.os.Bundle; +import android.util.Log; import android.view.View; +import android.widget.Button; +import android.widget.EditText; +import android.widget.Switch; + +import io.grpc.ManagedChannel; +import io.grpc.ManagedChannelBuilder; +import io.grpc.notifier.NotifierCommunicationGrpc; // SEE https://developer.android.com/training/notify-user/build-notification public class MainActivity extends AppCompatActivity { - private String CHANNEL_ID = "NOTIFIER_CHANNEL"; - private NotificationBroadcastReceiver br; + private final String CHANNEL_ID = "NOTIFIER_CHANNEL"; + private NotificationBroadcastReceiver br = null; + private ManagedChannel channel; + private NotifierCommunicationGrpc.NotifierCommunicationStub asyncStub; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); - // Register notification receiver - br = new NotificationBroadcastReceiver(); - IntentFilter intentFilter = new IntentFilter(); - intentFilter.addAction("com.mobilesec.client.notifier.NotifierService"); - LocalBroadcastManager.getInstance(this).registerReceiver(br, intentFilter); + Switch switchCommMode = this.findViewById(R.id.switchCommMode); + EditText textCommunicationId = this.findViewById(R.id.textCommunicationId); + textCommunicationId.setVisibility(View.GONE); + Button buttonConnect = this.findViewById(R.id.buttonConnect); + switchCommMode.setOnCheckedChangeListener((compoundButton, isChecked) -> { + if (isChecked) + { + textCommunicationId.setVisibility(View.VISIBLE); + buttonConnect.setText("Answer Communication"); + } + else + { + textCommunicationId.setVisibility(View.GONE); + buttonConnect.setText("Open Communication"); + } + }); createNotificationChannel(); } + private NotifierCommunicationGrpc.NotifierCommunicationStub connectServer(String host, int port) { + channel = ManagedChannelBuilder.forAddress(host, port).usePlaintext().build(); + Log.i("NOTIFIER[connectServer]", String.format("ConnectivityState: %s", channel.getState(true).name())); + asyncStub = NotifierCommunicationGrpc.newStub(channel); + return asyncStub; + } + + private void disconnectServer() { + channel.shutdownNow(); + channel = null; + Log.i("NOTIFIER[disconnectServer]", "Disconnected from server."); + } + private void createNotificationChannel() { // Create the NotificationChannel, but only on API 26+ because // the NotificationChannel class is new and not in the support library @@ -63,5 +97,37 @@ public class MainActivity extends AppCompatActivity { notificationManager.notify(1, builder.build()); } + public void connect(View view) { + EditText hostname = this.findViewById(R.id.textHostname); + EditText textPort = this.findViewById(R.id.textPort); + + int port = 0; + try { + port = Integer.parseInt(textPort.getText().toString()); + } catch(NumberFormatException e) { + Log.w("NOTIFIER[connect]", String.format("Failed to parse %s", e)); + return; + } + + // If a broadcast receiver already exists, unregister and discard + if (br != null) { + LocalBroadcastManager.getInstance(this).unregisterReceiver(br); + disconnectServer(); + } + + // Register new notification receiver with hostname and port + br = new NotificationBroadcastReceiver(connectServer(hostname.getText().toString(), port)); + IntentFilter intentFilter = new IntentFilter(); + intentFilter.addAction("com.mobilesec.client.notifier.NotifierService"); + LocalBroadcastManager.getInstance(this).registerReceiver(br, intentFilter); + } + + public void disconnect(View view) { + if (br != null) { + LocalBroadcastManager.getInstance(this).unregisterReceiver(br); + disconnectServer(); + br = null; + } + } } diff --git a/client/android/Notifier/app/src/main/java/com/mobilesec/client/notifier/NotificationBroadcastReceiver.java b/client/android/Notifier/app/src/main/java/com/mobilesec/client/notifier/NotificationBroadcastReceiver.java index 969916cee73a5f7b09980061b9bcf9f931d8ce79..352ac864e893b8af46d1afbc94cd2a2a62dec196 100644 --- a/client/android/Notifier/app/src/main/java/com/mobilesec/client/notifier/NotificationBroadcastReceiver.java +++ b/client/android/Notifier/app/src/main/java/com/mobilesec/client/notifier/NotificationBroadcastReceiver.java @@ -14,13 +14,10 @@ import io.grpc.stub.StreamObserver; public class NotificationBroadcastReceiver extends BroadcastReceiver { - private ManagedChannel channel; private final NotifierCommunicationGrpc.NotifierCommunicationStub asyncStub; - public NotificationBroadcastReceiver() { - channel = ManagedChannelBuilder.forAddress("192.168.0.127", 8080).usePlaintext().build(); - Log.i("NOTIFIER[NotificationBroadcastReceiver]", String.format("ConnectivityState: %s", channel.getState(true).name())); - asyncStub = NotifierCommunicationGrpc.newStub(channel); + public NotificationBroadcastReceiver(NotifierCommunicationGrpc.NotifierCommunicationStub asyncStub) { + this.asyncStub = asyncStub; } @Override @@ -38,7 +35,6 @@ public class NotificationBroadcastReceiver extends BroadcastReceiver { @Override public void onError(Throwable t) { Log.w("NOTIFIER[onReceive]", t); - Log.i("NOTIFIER[NotificationBroadcastReceiver]", String.format("ConnectivityState: %s", channel.getState(true).name())); Log.w("NOTIFIER[onReceive]", "Failed to send message."); } diff --git a/client/android/Notifier/app/src/main/res/layout/activity_main.xml b/client/android/Notifier/app/src/main/res/layout/activity_main.xml index b4904336a1f79eec7487c241babbe0ee534397fa..af2b951d5901f8fedfbe7bcf8374f8f78e50aea6 100644 --- a/client/android/Notifier/app/src/main/res/layout/activity_main.xml +++ b/client/android/Notifier/app/src/main/res/layout/activity_main.xml @@ -7,14 +7,97 @@ tools:context=".MainActivity"> <Button - android:id="@+id/button" + android:id="@+id/buttonBroadcastTestNotification" android:layout_width="365dp" - android:layout_height="53dp" - android:layout_marginStart="20dp" - android:layout_marginEnd="20dp" + android:layout_height="wrap_content" + android:layout_marginStart="24dp" + android:layout_marginTop="32dp" + android:layout_marginEnd="24dp" android:onClick="sendTestNotification" android:text="Broadcast test notification" app:layout_constraintEnd_toEndOf="parent" + app:layout_constraintHorizontal_bias="1.0" app:layout_constraintStart_toStartOf="parent" - tools:layout_editor_absoluteY="45dp" /> + app:layout_constraintTop_toTopOf="parent" /> + + <Button + android:id="@+id/buttonConnect" + android:layout_width="365dp" + android:layout_height="wrap_content" + android:layout_marginStart="24dp" + android:layout_marginTop="8dp" + android:layout_marginEnd="24dp" + android:onClick="connect" + android:text="Open communication" + app:layout_constraintEnd_toEndOf="parent" + app:layout_constraintHorizontal_bias="0.0" + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintTop_toBottomOf="@+id/textCommunicationId" /> + + <Button + android:id="@+id/buttonDisconnect" + android:layout_width="365dp" + android:layout_height="wrap_content" + android:layout_marginStart="24dp" + android:layout_marginTop="8dp" + android:layout_marginEnd="24dp" + android:onClick="disconnect" + android:text="Close communication" + app:layout_constraintEnd_toEndOf="parent" + app:layout_constraintHorizontal_bias="0.0" + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintTop_toBottomOf="@+id/buttonConnect" /> + + <EditText + android:id="@+id/textHostname" + android:layout_width="168dp" + android:layout_height="wrap_content" + android:layout_marginStart="24dp" + android:layout_marginTop="32dp" + android:ems="10" + android:hint="192.128.0.127" + android:inputType="textPersonName" + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintTop_toBottomOf="@+id/buttonBroadcastTestNotification" + tools:text="192.128.0.127" /> + + <EditText + android:id="@+id/textPort" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_marginStart="16dp" + android:layout_marginTop="32dp" + android:layout_marginEnd="24dp" + android:ems="10" + android:hint="8080" + android:inputType="number" + android:text="8080" + app:layout_constraintEnd_toEndOf="parent" + app:layout_constraintStart_toEndOf="@+id/textHostname" + app:layout_constraintTop_toBottomOf="@+id/buttonBroadcastTestNotification" /> + + <Switch + android:id="@+id/switchCommMode" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_marginStart="24dp" + android:layout_marginTop="16dp" + android:text=" Switch communication mode to answer" + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintTop_toBottomOf="@+id/textHostname" /> + + <EditText + android:id="@+id/textCommunicationId" + android:layout_width="360dp" + android:layout_height="wrap_content" + android:layout_marginStart="24dp" + android:layout_marginTop="8dp" + android:layout_marginEnd="24dp" + android:ems="10" + android:inputType="number" + android:visibility="visible" + app:layout_constraintEnd_toEndOf="parent" + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintTop_toBottomOf="@+id/switchCommMode" /> + </androidx.constraintlayout.widget.ConstraintLayout> \ No newline at end of file