Skip to content

Commit

Permalink
UnifiedPush
Browse files Browse the repository at this point in the history
  • Loading branch information
p1gp1g authored and valldrac committed Oct 22, 2024
1 parent 1258008 commit 315c012
Show file tree
Hide file tree
Showing 33 changed files with 1,270 additions and 7 deletions.
10 changes: 10 additions & 0 deletions app/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -122,6 +122,10 @@ android {
getByName("androidTest") {
java.srcDir("$projectDir/src/testShared")
}

getByName("main") {
java.srcDir("$projectDir/src/unifiedpush/java")
}
}

compileOptions {
Expand Down Expand Up @@ -532,6 +536,12 @@ dependencies {
implementation(libs.molly.glide.webp.decoder)
implementation(libs.gosimple.nbvcxz)
"fossImplementation"("org.osmdroid:osmdroid-android:6.1.16")
implementation(libs.unifiedpush.connector) {
exclude(group = "org.jetbrains.kotlin", module = "kotlin-stdlib")
}
implementation(libs.unifiedpush.connector.ui) {
exclude(group = "org.jetbrains.kotlin", module = "kotlin-stdlib")
}

"gmsImplementation"(project(":billing"))

Expand Down
1 change: 1 addition & 0 deletions app/proguard/proguard.cfg
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
-dontobfuscate
-keepattributes SourceFile,LineNumberTable
-keep class org.whispersystems.** { *; }
-keep class im.molly.** { *; }
-keep class org.signal.libsignal.net.** { *; }
-keep class org.signal.libsignal.protocol.** { *; }
-keep class org.signal.libsignal.usernames.** { *; }
Expand Down
12 changes: 12 additions & 0 deletions app/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
Expand Up @@ -1311,6 +1311,18 @@
</intent-filter>
</receiver>

<receiver
android:name="im.molly.unifiedpush.receiver.UnifiedPushReceiver"
android:enabled="true"
android:exported="true">
<intent-filter>
<action android:name="org.unifiedpush.android.connector.MESSAGE" />
<action android:name="org.unifiedpush.android.connector.UNREGISTERED" />
<action android:name="org.unifiedpush.android.connector.NEW_ENDPOINT" />
<action android:name="org.unifiedpush.android.connector.REGISTRATION_FAILED" />
</intent-filter>
</receiver>

<service
android:name=".gcm.FcmJobService"
android:permission="android.permission.BIND_JOB_SERVICE"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -119,6 +119,7 @@
import org.thoughtcrime.securesms.util.Util;
import org.thoughtcrime.securesms.util.dynamiclanguage.DynamicLanguageContextWrapper;

import im.molly.unifiedpush.util.UnifiedPushHelper;
import java.io.InterruptedIOException;
import java.net.SocketException;
import java.net.SocketTimeoutException;
Expand All @@ -127,6 +128,7 @@
import java.util.Map;
import java.util.concurrent.TimeUnit;

import im.molly.unifiedpush.jobs.UnifiedPushRefreshJob;
import io.reactivex.rxjava3.exceptions.OnErrorNotImplementedException;
import io.reactivex.rxjava3.exceptions.UndeliverableException;
import io.reactivex.rxjava3.plugins.RxJavaPlugins;
Expand Down Expand Up @@ -505,16 +507,20 @@ public void updatePushNotificationServices() {
}

boolean fcmEnabled = SignalStore.account().isFcmEnabled();
boolean forceWebSocket = SignalStore.internal().isWebsocketModeForced();
boolean unifiedPushEnabled = SignalStore.unifiedpush().isEnabled();
boolean forceWebSocket = !unifiedPushEnabled && SignalStore.internal().isWebsocketModeForced();
boolean forceFcm = !forceWebSocket && SignalStore.internal().isFcmModeForced();

if (forceWebSocket || !BuildConfig.USE_PLAY_SERVICES) {
if (unifiedPushEnabled || forceWebSocket || !BuildConfig.USE_PLAY_SERVICES) {
if (fcmEnabled) {
Log.i(TAG, "Play Services not allowed. Disabling FCM.");
updateFcmStatus(false);
} else {
Log.d(TAG, "FCM is disabled.");
}
if (unifiedPushEnabled) {
AppDependencies.getJobManager().add(new UnifiedPushRefreshJob());
}
} else if (forceFcm && !fcmEnabled && BuildConfig.USE_PLAY_SERVICES) {
Log.i(TAG, "FCM preferred. Updating to use FCM.");
updateFcmStatus(true);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,8 @@
import org.thoughtcrime.securesms.util.TextSecurePreferences;
import org.thoughtcrime.securesms.util.WindowUtil;

import static im.molly.unifiedpush.util.UnifiedPushHelper.registerAppWithDialogIfNeeded;

public class MainActivity extends PassphraseRequiredActivity implements VoiceNoteMediaControllerOwner {

public static final int RESULT_CONFIG_CHANGED = Activity.RESULT_FIRST_USER + 901;
Expand Down Expand Up @@ -109,6 +111,7 @@ public boolean onPreDraw() {
.getVitalsState()
.subscribe(this::presentVitalsState)
);
registerAppWithDialogIfNeeded(this);
}

@SuppressLint("NewApi")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -219,6 +219,22 @@ class InternalSettingsFragment : DSLSettingsFragment(R.string.preferences__inter
}
)

clickPref(
title = DSLSettingsText.from("Delete UnifiedPush ping"),
summary = DSLSettingsText.from("Make as Molly never received the ping from MollySocket. Will cause UnifiedPush to stop and Websocket to restart."),
onClick = {
MaterialAlertDialogBuilder(requireContext())
.setTitle("Delete UnifiedPush ping?")
.setMessage("Are you sure?")
.setPositiveButton(android.R.string.ok) { _, _ ->
SignalStore.unifiedpush.pinged = false
Toast.makeText(requireContext(), "UnifiedPush ping deleted!", Toast.LENGTH_SHORT).show()
}
.setNegativeButton(android.R.string.cancel, null)
.show()
}
)

dividerPref()

sectionHeaderPref(DSLSettingsText.from("Logging"))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ import org.thoughtcrime.securesms.keyvalue.SignalStore
import org.thoughtcrime.securesms.notifications.NotificationChannels
import org.thoughtcrime.securesms.notifications.TurnOnNotificationsBottomSheet
import org.thoughtcrime.securesms.util.BottomSheetUtil
import org.thoughtcrime.securesms.util.CommunicationActions
import org.thoughtcrime.securesms.util.PlayServicesUtil
import org.thoughtcrime.securesms.util.RingtoneUtil
import org.thoughtcrime.securesms.util.SecurePreferenceManager
Expand Down Expand Up @@ -356,6 +357,7 @@ class NotificationsSettingsFragment : DSLSettingsFragment(R.string.preferences__
val showAlertIcon = when (state.preferredNotificationMethod) {
NotificationDeliveryMethod.FCM -> !state.canReceiveFcm
NotificationDeliveryMethod.WEBSOCKET -> false
NotificationDeliveryMethod.UNIFIEDPUSH -> !state.canReceiveUnifiedPush
}
radioListPref(
title = DSLSettingsText.from(R.string.NotificationsSettingsFragment__delivery_service),
Expand All @@ -367,6 +369,14 @@ class NotificationsSettingsFragment : DSLSettingsFragment(R.string.preferences__
onNotificationMethodChanged(notificationMethodValues[it], state.preferredNotificationMethod)
}
)

clickPref(
title = DSLSettingsText.from(R.string.NotificationsSettingsFragment__configure_unifiedpush),
isEnabled = state.preferredNotificationMethod == NotificationDeliveryMethod.UNIFIEDPUSH,
onClick = {
navigateToUnifiedPushSettings()
}
)
}
}

Expand All @@ -392,9 +402,32 @@ class NotificationsSettingsFragment : DSLSettingsFragment(R.string.preferences__
NotificationDeliveryMethod.WEBSOCKET -> {
viewModel.setPreferredNotificationMethod(method)
}

NotificationDeliveryMethod.UNIFIEDPUSH -> {
if (method != previousMethod) {
MaterialAlertDialogBuilder(requireContext())
.setTitle(R.string.NotificationsSettingsFragment__mollysocket_server)
.setMessage(R.string.NotificationsSettingsFragment__to_use_unifiedpush_you_need_a_mollysocket_server)
.setPositiveButton(R.string.yes) { _, _ ->
viewModel.setPreferredNotificationMethod(method)
navigateToUnifiedPushSettings()
}
.setNegativeButton(R.string.no, null)
.setNeutralButton(R.string.LearnMoreTextView_learn_more) { _, _ ->
CommunicationActions.openBrowserLink(requireContext(), getString(R.string.mollysocket_setup_url))
}
.show()
} else {
navigateToUnifiedPushSettings()
}
}
}
}

private fun navigateToUnifiedPushSettings() {
findNavController().safeNavigate(R.id.action_notificationsSettingsFragment_to_unifiedPushFragment)
}

private fun getRingtoneSummary(uri: Uri): String {
return if (TextUtils.isEmpty(uri.toString())) {
getString(R.string.preferences__silent)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,8 @@ data class NotificationsSettingsState(
val notifyWhenContactJoinsSignal: Boolean,
val isLinkedDevice: Boolean,
val preferredNotificationMethod: NotificationDeliveryMethod,
val canReceiveFcm: Boolean
val canReceiveFcm: Boolean,
val canReceiveUnifiedPush: Boolean
)

data class MessageNotificationsState(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -162,6 +162,7 @@ class NotificationsSettingsViewModel(private val sharedPreferences: SharedPrefer
isLinkedDevice = SignalStore.account.isLinkedDevice,
preferredNotificationMethod = SignalStore.settings.preferredNotificationMethod,
canReceiveFcm = SignalStore.account.canReceiveFcm,
canReceiveUnifiedPush = SignalStore.unifiedpush.isAvailableOrAirGapped
)

private fun canEnableNotifications(): Boolean {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,8 @@ public void onSendError(@NonNull String s, @NonNull Exception e) {
Log.w(TAG, "onSendError()", e);
}

private static void handleReceivedNotification(Context context, @Nullable RemoteMessage remoteMessage) {
// MOLLY: Make this function public to use it from UnifiedPushReceiver
public static void handleReceivedNotification(Context context, @Nullable RemoteMessage remoteMessage) {
boolean highPriority = remoteMessage != null && remoteMessage.getPriority() == RemoteMessage.PRIORITY_HIGH;
try {
Log.d(TAG, String.format(Locale.US, "[handleReceivedNotification] API: %s, RemoteMessagePriority: %s", Build.VERSION.SDK_INT, remoteMessage != null ? remoteMessage.getPriority() : "n/a"));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,8 @@
import java.util.List;
import java.util.Map;

import im.molly.unifiedpush.jobs.UnifiedPushRefreshJob;

public final class JobManagerFactories {

public static Map<String, Job.Factory> getJobFactories(@NonNull Application application) {
Expand Down Expand Up @@ -142,6 +144,7 @@ public static Map<String, Job.Factory> getJobFactories(@NonNull Application appl
put(DownloadLatestEmojiDataJob.KEY, new DownloadLatestEmojiDataJob.Factory());
put(EmojiSearchIndexDownloadJob.KEY, new EmojiSearchIndexDownloadJob.Factory());
put(FcmRefreshJob.KEY, new FcmRefreshJob.Factory());
put(UnifiedPushRefreshJob.KEY, new UnifiedPushRefreshJob.Factory());
put(FetchRemoteMegaphoneImageJob.KEY, new FetchRemoteMegaphoneImageJob.Factory());
put(FontDownloaderJob.KEY, new FontDownloaderJob.Factory());
put(ForceUpdateGroupV2Job.KEY, new ForceUpdateGroupV2Job.Factory());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -317,7 +317,7 @@ class AccountValues internal constructor(store: KeyValueStore, context: Context)

@get:JvmName("isPushAvailable")
val pushAvailable: Boolean
get() = canReceiveFcm
get() = canReceiveFcm || SignalStore.unifiedpush.isAvailableOrAirGapped

/** The FCM token, which allows the server to send us FCM messages. */
var fcmToken: String?
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -564,7 +564,7 @@ public enum Theme {
}

public enum NotificationDeliveryMethod {
FCM, WEBSOCKET;
FCM, WEBSOCKET, UNIFIEDPUSH;

public @NonNull String serialize() {
return name();
Expand All @@ -578,6 +578,7 @@ public enum NotificationDeliveryMethod {
return switch (this) {
case FCM -> R.string.NotificationDeliveryMethod__fcm;
case WEBSOCKET -> R.string.NotificationDeliveryMethod__websocket;
case UNIFIEDPUSH -> R.string.NotificationDeliveryMethod__unifiedpush;
};
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ class SignalStore(context: Application, private val store: KeyValueStore) {
val storyValues = StoryValues(store)
val apkUpdateValues = ApkUpdateValues(store)
val backupValues = BackupValues(store)
val unifiedPushValues = UnifiedPushValues(store)

val plainTextValues = PlainTextSharedPrefsDataStore(context)

Expand Down Expand Up @@ -258,6 +259,11 @@ class SignalStore(context: Application, private val store: KeyValueStore) {
val backup: BackupValues
get() = instance!!.backupValues

@JvmStatic
@get:JvmName("unifiedpush")
val unifiedpush: UnifiedPushValues
get() = instance!!.unifiedPushValues

val groupsV2AciAuthorizationCache: GroupsV2AuthorizationSignalStoreCache
get() = GroupsV2AuthorizationSignalStoreCache.createAciCache(instance!!.store)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,7 @@ public class LogSectionSystemInfo implements LogSection {
builder.append("Network Status : ").append(NetworkUtil.getNetworkStatus(context)).append("\n");
builder.append("Play Services : ").append(getPlayServicesString(context)).append("\n");
builder.append("FCM : ").append(locked ? "Unknown" : SignalStore.account().isFcmEnabled()).append("\n");
builder.append("UnifiedPush : ").append(locked ? "Unknown" : SignalStore.unifiedpush().isEnabled()).append("\n");
builder.append("Locale : ").append(Locale.getDefault()).append("\n");
builder.append("Linked Devices : ").append(locked ? "Unknown" : TextSecurePreferences.isMultiDevice(context)).append("\n");
builder.append("First Version : ").append(TextSecurePreferences.getFirstInstallVersion(context)).append("\n");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -587,7 +587,6 @@ object RegistrationRepository {
return started == true
}

@VisibleForTesting
fun generateSignedAndLastResortPreKeys(identity: IdentityKeyPair, metadataStore: PreKeyMetadataStore): PreKeyCollection {
val signedPreKey = PreKeyUtil.generateSignedPreKey(metadataStore.nextSignedPreKeyId, identity.privateKey)
val lastResortKyberPreKey = PreKeyUtil.generateLastResortKyberPreKey(metadataStore.nextKyberPreKeyId, identity.privateKey)
Expand Down
13 changes: 13 additions & 0 deletions app/src/main/res/navigation/app_settings_with_change_number.xml
Original file line number Diff line number Diff line change
Expand Up @@ -450,6 +450,14 @@
app:popEnterAnim="@anim/fragment_close_enter"
app:popExitAnim="@anim/fragment_close_exit" />

<action
android:id="@+id/action_notificationsSettingsFragment_to_unifiedPushFragment"
app:destination="@id/notificationUnifiedPushFragment"
app:enterAnim="@anim/fragment_open_enter"
app:exitAnim="@anim/fragment_open_exit"
app:popEnterAnim="@anim/fragment_close_enter"
app:popExitAnim="@anim/fragment_close_exit" />

<argument
android:name="scroll_to_push_services"
android:defaultValue="false"
Expand Down Expand Up @@ -878,6 +886,11 @@
app:popExitAnim="@anim/fragment_close_exit" />
</fragment>

<!-- UnifiedPush -->
<fragment
android:id="@+id/notificationUnifiedPushFragment"
android:name="im.molly.unifiedpush.components.settings.app.notifications.UnifiedPushSettingsFragment" />

<fragment
android:id="@+id/editNotificationProfileFragment"
android:name="org.thoughtcrime.securesms.components.settings.app.notifications.profiles.EditNotificationProfileFragment"
Expand Down
Loading

0 comments on commit 315c012

Please sign in to comment.