diff --git a/briar-android/src/main/java/org/briarproject/briar/android/AndroidNotificationManagerImpl.java b/briar-android/src/main/java/org/briarproject/briar/android/AndroidNotificationManagerImpl.java
index f7a175805..1cd973ab8 100644
--- a/briar-android/src/main/java/org/briarproject/briar/android/AndroidNotificationManagerImpl.java
+++ b/briar-android/src/main/java/org/briarproject/briar/android/AndroidNotificationManagerImpl.java
@@ -30,6 +30,7 @@ import org.briarproject.bramble.util.StringUtils;
import org.briarproject.briar.R;
import org.briarproject.briar.android.conversation.ConversationActivity;
import org.briarproject.briar.android.forum.ForumActivity;
+import org.briarproject.briar.android.hotspot.HotspotActivity;
import org.briarproject.briar.android.login.SignInReminderReceiver;
import org.briarproject.briar.android.navdrawer.NavDrawerActivity;
import org.briarproject.briar.android.privategroup.conversation.GroupActivity;
@@ -63,9 +64,11 @@ import static android.app.Notification.DEFAULT_SOUND;
import static android.app.Notification.DEFAULT_VIBRATE;
import static android.app.NotificationManager.IMPORTANCE_DEFAULT;
import static android.app.NotificationManager.IMPORTANCE_LOW;
+import static android.app.PendingIntent.getActivity;
import static android.content.Context.NOTIFICATION_SERVICE;
import static android.content.Intent.FLAG_ACTIVITY_CLEAR_TOP;
import static android.content.Intent.FLAG_ACTIVITY_NEW_TASK;
+import static android.content.Intent.FLAG_ACTIVITY_SINGLE_TOP;
import static android.os.Build.VERSION.SDK_INT;
import static androidx.core.app.NotificationCompat.CATEGORY_MESSAGE;
import static androidx.core.app.NotificationCompat.CATEGORY_SERVICE;
@@ -274,7 +277,7 @@ class AndroidNotificationManagerImpl implements AndroidNotificationManager,
b.setWhen(0); // Don't show the time
b.setOngoing(true);
Intent i = new Intent(appContext, SplashScreenActivity.class);
- b.setContentIntent(PendingIntent.getActivity(appContext, 0, i, 0));
+ b.setContentIntent(getActivity(appContext, 0, i, 0));
if (SDK_INT >= 21) {
b.setCategory(CATEGORY_SERVICE);
b.setVisibility(VISIBILITY_SECRET);
@@ -619,13 +622,11 @@ class AndroidNotificationManagerImpl implements AndroidNotificationManager,
public void showSignInNotification() {
if (blockSignInReminder) return;
if (SDK_INT >= 26) {
- NotificationChannel channel =
- new NotificationChannel(REMINDER_CHANNEL_ID, appContext
- .getString(
- R.string.reminder_notification_channel_title),
- IMPORTANCE_LOW);
- channel.setLockscreenVisibility(
- NotificationCompat.VISIBILITY_SECRET);
+ NotificationChannel channel = new NotificationChannel(
+ REMINDER_CHANNEL_ID, appContext
+ .getString(R.string.reminder_notification_channel_title),
+ IMPORTANCE_LOW);
+ channel.setLockscreenVisibility(VISIBILITY_SECRET);
notificationManager.createNotificationChannel(channel);
}
@@ -652,7 +653,7 @@ class AndroidNotificationManagerImpl implements AndroidNotificationManager,
Intent i = new Intent(appContext, SplashScreenActivity.class);
i.setFlags(FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_CLEAR_TOP);
- b.setContentIntent(PendingIntent.getActivity(appContext, 0, i, 0));
+ b.setContentIntent(getActivity(appContext, 0, i, 0));
notificationManager.notify(REMINDER_NOTIFICATION_ID, b.build());
}
@@ -720,4 +721,39 @@ class AndroidNotificationManagerImpl implements AndroidNotificationManager,
public void unblockAllBlogPostNotifications() {
androidExecutor.runOnUiThread((Runnable) () -> blockBlogs = false);
}
+
+ @Override
+ public void showHotspotNotification() {
+ if (SDK_INT >= 26) {
+ String channelTitle = appContext
+ .getString(R.string.hotspot_notification_channel_title);
+ NotificationChannel channel = new NotificationChannel(
+ HOTSPOT_CHANNEL_ID, channelTitle, IMPORTANCE_LOW);
+ channel.setLockscreenVisibility(VISIBILITY_SECRET);
+ notificationManager.createNotificationChannel(channel);
+ }
+ BriarNotificationBuilder b =
+ new BriarNotificationBuilder(appContext, HOTSPOT_CHANNEL_ID);
+ b.setSmallIcon(R.drawable.ic_wifi_tethering);
+ b.setColorRes(R.color.briar_brand_green);
+ b.setContentTitle(
+ appContext.getText(R.string.hotspot_notification_title));
+ b.setNotificationCategory(CATEGORY_SERVICE);
+ b.setOngoing(true);
+ b.setShowWhen(true);
+
+ String actionTitle =
+ appContext.getString(R.string.hotspot_button_stop_sharing);
+ Intent i = new Intent(appContext, HotspotActivity.class);
+ i.addFlags(FLAG_ACTIVITY_SINGLE_TOP);
+ i.setAction(ACTION_STOP_HOTSPOT);
+ PendingIntent actionIntent = getActivity(appContext, 0, i, 0);
+ b.addAction(R.drawable.ic_portable_wifi_off, actionTitle, actionIntent);
+ notificationManager.notify(HOTSPOT_NOTIFICATION_ID, b.build());
+ }
+
+ @Override
+ public void clearHotspotNotification() {
+ notificationManager.cancel(HOTSPOT_NOTIFICATION_ID);
+ }
}
diff --git a/briar-android/src/main/java/org/briarproject/briar/android/hotspot/AbstractTabsFragment.java b/briar-android/src/main/java/org/briarproject/briar/android/hotspot/AbstractTabsFragment.java
index 982d538b9..2056f0002 100644
--- a/briar-android/src/main/java/org/briarproject/briar/android/hotspot/AbstractTabsFragment.java
+++ b/briar-android/src/main/java/org/briarproject/briar/android/hotspot/AbstractTabsFragment.java
@@ -9,7 +9,6 @@ import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Button;
-import android.widget.Toast;
import com.google.android.material.tabs.TabLayout;
import com.google.android.material.tabs.TabLayoutMediator;
@@ -28,7 +27,7 @@ import androidx.lifecycle.ViewModelProvider;
import androidx.viewpager2.adapter.FragmentStateAdapter;
import androidx.viewpager2.widget.ViewPager2;
-import static android.widget.Toast.LENGTH_SHORT;
+import static androidx.core.app.ActivityCompat.finishAfterTransition;
import static org.briarproject.briar.android.AppModule.getAndroidComponent;
@MethodsNotNullByDefault
@@ -81,8 +80,8 @@ public abstract class AbstractTabsFragment extends Fragment {
stopButton = view.findViewById(R.id.stopButton);
stopButton.setOnClickListener(v -> {
- Toast.makeText(requireContext(), "Not yet implemented",
- LENGTH_SHORT).show();
+ // also clears hotspot
+ finishAfterTransition(requireActivity());
});
connectedButton = view.findViewById(R.id.connectedButton);
}
diff --git a/briar-android/src/main/java/org/briarproject/briar/android/hotspot/HotspotActivity.java b/briar-android/src/main/java/org/briarproject/briar/android/hotspot/HotspotActivity.java
index 28d643d9e..cde183485 100644
--- a/briar-android/src/main/java/org/briarproject/briar/android/hotspot/HotspotActivity.java
+++ b/briar-android/src/main/java/org/briarproject/briar/android/hotspot/HotspotActivity.java
@@ -1,5 +1,6 @@
package org.briarproject.briar.android.hotspot;
+import android.content.Intent;
import android.os.Bundle;
import android.view.MenuItem;
@@ -16,6 +17,8 @@ import androidx.annotation.NonNull;
import androidx.appcompat.app.ActionBar;
import androidx.lifecycle.ViewModelProvider;
+import static org.briarproject.briar.api.android.AndroidNotificationManager.ACTION_STOP_HOTSPOT;
+
@MethodsNotNullByDefault
@ParametersNotNullByDefault
public class HotspotActivity extends BriarActivity {
@@ -61,4 +64,13 @@ public class HotspotActivity extends BriarActivity {
return super.onOptionsItemSelected(item);
}
+ @Override
+ protected void onNewIntent(Intent intent) {
+ super.onNewIntent(intent);
+ if (ACTION_STOP_HOTSPOT.equals(intent.getAction())) {
+ // also closes hotspot
+ supportFinishAfterTransition();
+ }
+ }
+
}
diff --git a/briar-android/src/main/java/org/briarproject/briar/android/hotspot/HotspotIntroFragment.java b/briar-android/src/main/java/org/briarproject/briar/android/hotspot/HotspotIntroFragment.java
index 58ce3d323..ab32ac6c6 100644
--- a/briar-android/src/main/java/org/briarproject/briar/android/hotspot/HotspotIntroFragment.java
+++ b/briar-android/src/main/java/org/briarproject/briar/android/hotspot/HotspotIntroFragment.java
@@ -61,6 +61,7 @@ public class HotspotIntroFragment extends Fragment {
progressTextView.setVisibility(VISIBLE);
// TODO remove below, tell viewModel to start hotspot instead
v.postDelayed(() -> {
+ viewModel.startHotspot();
getParentFragmentManager().beginTransaction()
.setCustomAnimations(R.anim.step_next_in,
R.anim.step_previous_out,
diff --git a/briar-android/src/main/java/org/briarproject/briar/android/hotspot/HotspotViewModel.java b/briar-android/src/main/java/org/briarproject/briar/android/hotspot/HotspotViewModel.java
index 60b006377..4dfc3c733 100644
--- a/briar-android/src/main/java/org/briarproject/briar/android/hotspot/HotspotViewModel.java
+++ b/briar-android/src/main/java/org/briarproject/briar/android/hotspot/HotspotViewModel.java
@@ -8,6 +8,7 @@ import org.briarproject.bramble.api.lifecycle.LifecycleManager;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
import org.briarproject.bramble.api.system.AndroidExecutor;
import org.briarproject.briar.android.viewmodel.DbViewModel;
+import org.briarproject.briar.api.android.AndroidNotificationManager;
import java.util.concurrent.Executor;
@@ -16,13 +17,31 @@ import javax.inject.Inject;
@NotNullByDefault
class HotspotViewModel extends DbViewModel {
+ private final AndroidNotificationManager notificationManager;
+
@Inject
HotspotViewModel(Application application,
@DatabaseExecutor Executor dbExecutor,
LifecycleManager lifecycleManager,
TransactionManager db,
- AndroidExecutor androidExecutor) {
+ AndroidExecutor androidExecutor,
+ AndroidNotificationManager notificationManager) {
super(application, dbExecutor, lifecycleManager, db, androidExecutor);
+ this.notificationManager = notificationManager;
+ }
+
+ void startHotspot() {
+ notificationManager.showHotspotNotification();
+ }
+
+ private void stopHotspot() {
+ notificationManager.clearHotspotNotification();
+ }
+
+ @Override
+ protected void onCleared() {
+ super.onCleared();
+ stopHotspot();
}
// TODO copy actual code from Offline Hotspot app
diff --git a/briar-android/src/main/java/org/briarproject/briar/api/android/AndroidNotificationManager.java b/briar-android/src/main/java/org/briarproject/briar/api/android/AndroidNotificationManager.java
index 765425720..908b27322 100644
--- a/briar-android/src/main/java/org/briarproject/briar/api/android/AndroidNotificationManager.java
+++ b/briar-android/src/main/java/org/briarproject/briar/api/android/AndroidNotificationManager.java
@@ -31,6 +31,7 @@ public interface AndroidNotificationManager {
int FORUM_POST_NOTIFICATION_ID = 6;
int BLOG_POST_NOTIFICATION_ID = 7;
int CONTACT_ADDED_NOTIFICATION_ID = 8;
+ int HOTSPOT_NOTIFICATION_ID = 9;
// Channel IDs
String CONTACT_CHANNEL_ID = "contacts";
@@ -42,12 +43,15 @@ public interface AndroidNotificationManager {
String ONGOING_CHANNEL_OLD_ID = "zForegroundService";
String ONGOING_CHANNEL_ID = "zForegroundService2";
String REMINDER_CHANNEL_ID = "zSignInReminder";
+ String HOTSPOT_CHANNEL_ID = "zHotspot";
+
// This channel is no longer used - keep the ID so we can remove the
// channel from existing installations
String FAILURE_CHANNEL_ID = "zStartupFailure";
// Actions for pending intents
String ACTION_DISMISS_REMINDER = "dismissReminder";
+ String ACTION_STOP_HOTSPOT = "stopHotspot";
Notification getForegroundNotification();
@@ -96,4 +100,8 @@ public interface AndroidNotificationManager {
void blockAllBlogPostNotifications();
void unblockAllBlogPostNotifications();
+
+ void showHotspotNotification();
+
+ void clearHotspotNotification();
}
diff --git a/briar-android/src/main/res/values/strings.xml b/briar-android/src/main/res/values/strings.xml
index 616909ba7..763954acb 100644
--- a/briar-android/src/main/res/values/strings.xml
+++ b/briar-android/src/main/res/values/strings.xml
@@ -699,6 +699,8 @@
Start sharing
Stop sharing
Setting up hotspot…
+ Wi-Fi hotspot
+ Sharing Briar offline
Confirm connection
Manual
To download the app on another phone, please connect to this Wi-Fi network: