diff --git a/CHANGELOG.md b/CHANGELOG.md index 83847dc6..7dec2078 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,8 +1,13 @@ +# Build 202 (0.14.1) +2023-05-15 + +- Bug fixes + # Build 201 (0.14.0) 2023-04-19 -- dependency updates -- various fixes +- Dependency updates +- Various fixes # ~~Build 200 (0.14.0)~~ 2023-04-05 diff --git a/obv_engine/engine/src/main/java/io/olvid/engine/channel/databases/ObliviousChannel.java b/obv_engine/engine/src/main/java/io/olvid/engine/channel/databases/ObliviousChannel.java index f7a5ae8e..f38799d6 100644 --- a/obv_engine/engine/src/main/java/io/olvid/engine/channel/databases/ObliviousChannel.java +++ b/obv_engine/engine/src/main/java/io/olvid/engine/channel/databases/ObliviousChannel.java @@ -605,7 +605,7 @@ public void wasCommitted() { if ((commitHookBits & HOOK_BIT_CHANNEL_CONFIRMED) != 0) { // refresh members of groups owned by the remoteIdentity (useful after a backup restore) channelManagerSession.identityDelegate.refreshMembersOfGroupsOwnedByGroupOwner(currentDeviceUid, remoteIdentity); - // reinvite members of groups owned (useful after a backup restore) + // re-invite members of groups owned (useful after a backup restore) channelManagerSession.identityDelegate.pushMembersOfOwnedGroupsToContact(currentDeviceUid, remoteIdentity); // resend a batch of all keys for common groups V2 channelManagerSession.identityDelegate.initiateGroupV2BatchKeysResend(currentDeviceUid, remoteIdentity, remoteDeviceUid); diff --git a/obv_engine/engine/src/main/java/io/olvid/engine/identity/IdentityManager.java b/obv_engine/engine/src/main/java/io/olvid/engine/identity/IdentityManager.java index f71025d6..867f348a 100644 --- a/obv_engine/engine/src/main/java/io/olvid/engine/identity/IdentityManager.java +++ b/obv_engine/engine/src/main/java/io/olvid/engine/identity/IdentityManager.java @@ -1594,7 +1594,7 @@ public boolean reBlockForcefullyUnblockedContact(Session session, Identity owned @Override - public void addDeviceForContactIdentity(Session session, Identity ownedIdentity, Identity contactIdentity, UID deviceUid) throws SQLException { + public boolean addDeviceForContactIdentity(Session session, Identity ownedIdentity, Identity contactIdentity, UID deviceUid) throws SQLException { ContactIdentity contact = ContactIdentity.get(wrapSession(session), ownedIdentity, contactIdentity); if (contact != null && contact.isActive()) { ContactDevice contactDevice = ContactDevice.get(wrapSession(session), deviceUid, contactIdentity, ownedIdentity); @@ -1604,8 +1604,10 @@ public void addDeviceForContactIdentity(Session session, Identity ownedIdentity, if (contactDevice == null) { throw new SQLException(); } + return true; } } + return false; } @Override @@ -3359,6 +3361,15 @@ private void moveKeycloakMemberToPendingMember(IdentityManagerSession identityMa }); } + // return true only if the identity is a PendingMember: if it is a GroupMember, it returns false + @Override + public boolean isIdentityAPendingGroupV2Member(Session session, Identity ownedIdentity, GroupV2.Identifier groupIdentifier, Identity identity) throws SQLException { + if (session == null || ownedIdentity == null || groupIdentifier == null || identity == null) { + return false; + } + + return ContactGroupV2PendingMember.get(wrapSession(session), ownedIdentity, groupIdentifier, identity) != null; + } // endregion diff --git a/obv_engine/engine/src/main/java/io/olvid/engine/metamanager/IdentityDelegate.java b/obv_engine/engine/src/main/java/io/olvid/engine/metamanager/IdentityDelegate.java index 620cf066..65905ddc 100644 --- a/obv_engine/engine/src/main/java/io/olvid/engine/metamanager/IdentityDelegate.java +++ b/obv_engine/engine/src/main/java/io/olvid/engine/metamanager/IdentityDelegate.java @@ -137,7 +137,8 @@ public interface IdentityDelegate { boolean forcefullyUnblockContact(Session session, Identity ownedIdentity, Identity contactIdentity) throws SQLException; boolean reBlockForcefullyUnblockedContact(Session session, Identity ownedIdentity, Identity contactIdentity) throws SQLException; - void addDeviceForContactIdentity(Session session, Identity ownedIdentity, Identity contactIdentity, UID deviceUid) throws SQLException; + // return true if a device was indeed added, false if the device already existed, and throws an exception if adding the device failed + boolean addDeviceForContactIdentity(Session session, Identity ownedIdentity, Identity contactIdentity, UID deviceUid) throws SQLException; void removeDeviceForContactIdentity(Session session, Identity ownedIdentity, Identity contactIdentity, UID deviceUid) throws SQLException; void removeAllDevicesForContactIdentity(Session session, Identity ownedIdentity, Identity contactIdentity) throws SQLException; UID[] getDeviceUidsOfContactIdentity(Session session, Identity ownedIdentity, Identity contactIdentity) throws SQLException; @@ -223,7 +224,7 @@ public interface IdentityDelegate { byte[] createKeycloakGroupV2(Session session, Identity ownedIdentity, GroupV2.Identifier groupIdentifier, KeycloakGroupBlob keycloakGroupBlob); KeycloakGroupV2UpdateOutput updateKeycloakGroupV2WithNewBlob(Session session, Identity ownedIdentity, GroupV2.Identifier groupIdentifier, KeycloakGroupBlob keycloakGroupBlob) throws Exception; void rePingOrDemoteContactFromAllKeycloakGroups(Session session, Identity ownedIdentity, Identity contactIdentity, boolean certifiedByOwnKeycloak, String lastKnownSerializedCertifiedDetails) throws SQLException; - + boolean isIdentityAPendingGroupV2Member(Session session, Identity ownedIdentity, GroupV2.Identifier groupIdentifier, Identity obliviousChannelContactIdentity) throws SQLException; // endregion diff --git a/obv_engine/engine/src/main/java/io/olvid/engine/protocol/protocols/ChannelCreationWithContactDeviceProtocol.java b/obv_engine/engine/src/main/java/io/olvid/engine/protocol/protocols/ChannelCreationWithContactDeviceProtocol.java index 57af465b..afdf38ba 100644 --- a/obv_engine/engine/src/main/java/io/olvid/engine/protocol/protocols/ChannelCreationWithContactDeviceProtocol.java +++ b/obv_engine/engine/src/main/java/io/olvid/engine/protocol/protocols/ChannelCreationWithContactDeviceProtocol.java @@ -997,9 +997,16 @@ public ConcreteProtocolState executeStep() throws Exception { return new CancelledState(); } - // add the contact deviceUid if not already there --> we no longer trigger a device discovery + // Add the contactDeviceUid to the contactIdentity if needed --> If the device was indeed added, trigger a device discovery try { - protocolManagerSession.identityDelegate.addDeviceForContactIdentity(protocolManagerSession.session, getOwnedIdentity(), startState.contactIdentity, startState.contactDeviceUid); + if (protocolManagerSession.identityDelegate.addDeviceForContactIdentity(protocolManagerSession.session, getOwnedIdentity(), startState.contactIdentity, startState.contactDeviceUid)) { + CoreProtocolMessage coreProtocolMessage = new CoreProtocolMessage(SendChannelInfo.createLocalChannelInfo(getOwnedIdentity()), + ConcreteProtocol.DEVICE_DISCOVERY_PROTOCOL_ID, + new UID(getPrng()), + false); + ChannelMessageToSend messageToSend = new DeviceDiscoveryProtocol.InitialMessage(coreProtocolMessage, startState.contactIdentity).generateChannelProtocolMessageToSend(); + protocolManagerSession.channelDelegate.post(protocolManagerSession.session, messageToSend, getPrng()); + } } catch (Exception e) { Logger.w("Exception when adding a contact device"); } @@ -1065,9 +1072,16 @@ public ConcreteProtocolState executeStep() throws Exception { return new CancelledState(); } - // Add the contactDeviceUid to the contactIdentity if needed --> we no longer trigger a device discovery + // Add the contactDeviceUid to the contactIdentity if needed --> If the device was indeed added, trigger a device discovery try { - protocolManagerSession.identityDelegate.addDeviceForContactIdentity(protocolManagerSession.session, getOwnedIdentity(), startState.contactIdentity, startState.contactDeviceUid); + if (protocolManagerSession.identityDelegate.addDeviceForContactIdentity(protocolManagerSession.session, getOwnedIdentity(), startState.contactIdentity, startState.contactDeviceUid)) { + CoreProtocolMessage coreProtocolMessage = new CoreProtocolMessage(SendChannelInfo.createLocalChannelInfo(getOwnedIdentity()), + ConcreteProtocol.DEVICE_DISCOVERY_PROTOCOL_ID, + new UID(getPrng()), + false); + ChannelMessageToSend messageToSend = new DeviceDiscoveryProtocol.InitialMessage(coreProtocolMessage, startState.contactIdentity).generateChannelProtocolMessageToSend(); + protocolManagerSession.channelDelegate.post(protocolManagerSession.session, messageToSend, getPrng()); + } } catch (Exception e) { Logger.w("Exception when adding a contact device"); } diff --git a/obv_engine/engine/src/main/java/io/olvid/engine/protocol/protocols/GroupsV2Protocol.java b/obv_engine/engine/src/main/java/io/olvid/engine/protocol/protocols/GroupsV2Protocol.java index 901cc0e9..2d84132f 100644 --- a/obv_engine/engine/src/main/java/io/olvid/engine/protocol/protocols/GroupsV2Protocol.java +++ b/obv_engine/engine/src/main/java/io/olvid/engine/protocol/protocols/GroupsV2Protocol.java @@ -2313,8 +2313,8 @@ public ConcreteProtocolState executeStep() throws Exception { } { - // check if we already have a more recent group version invitation if (startState instanceof InvitationReceivedState) { + // if still in InvitationReceivedState, check the version and trigger a re-download if necessary if (((InvitationReceivedState) startState).serverBlob.version >= groupVersion) { return startState; } @@ -2349,14 +2349,36 @@ public ConcreteProtocolState executeStep() throws Exception { } } - // check if we already joined this group and have a larger group version + // check if we already joined this group Integer dbGroupVersion = protocolManagerSession.identityDelegate.getGroupV2Version(protocolManagerSession.session, getOwnedIdentity(), groupIdentifier); - if (dbGroupVersion != null && dbGroupVersion >= groupVersion) { - // we already have a more recent version of this group, ignore the message - if (startState != null) { - return startState; - } else { - return new FinalState(); + if (dbGroupVersion != null) { + // if we joined this group and the obliviousChannelContactIdentity is still a pending member, there is a problem! We send him a ping + if (dbGroupVersion <= groupVersion && obliviousChannelContactIdentity != null && protocolManagerSession.identityDelegate.isIdentityAPendingGroupV2Member(protocolManagerSession.session, getOwnedIdentity(), groupIdentifier, obliviousChannelContactIdentity)) { + byte[] ownGroupInvitationNonce = protocolManagerSession.identityDelegate.getGroupV2OwnGroupInvitationNonce(protocolManagerSession.session, getOwnedIdentity(), groupIdentifier); + if (ownGroupInvitationNonce != null) { + byte[] pingSignature = protocolManagerSession.identityDelegate.signGroupInvitationNonce( + protocolManagerSession.session, + Constants.SignatureContext.GROUP_JOIN_NONCE, + groupIdentifier, + ownGroupInvitationNonce, + obliviousChannelContactIdentity, + getOwnedIdentity(), + getPrng()); + + CoreProtocolMessage coreProtocolMessage = buildCoreProtocolMessage(SendChannelInfo.createAsymmetricBroadcastChannelInfo(obliviousChannelContactIdentity, getOwnedIdentity())); + ChannelMessageToSend messageToSend = new PingMessage(coreProtocolMessage, groupIdentifier, ownGroupInvitationNonce, pingSignature, false).generateChannelProtocolMessageToSend(); + protocolManagerSession.channelDelegate.post(protocolManagerSession.session, messageToSend, getPrng()); + } + } + + + if (dbGroupVersion >= groupVersion) { + // we already have a more recent version of this group, ignore the message + if (startState != null) { + return startState; + } else { + return new FinalState(); + } } } @@ -3037,6 +3059,7 @@ public static class InitiateBlobReDownloadStep extends ProtocolStep { private final UUID dialogUuid; private final GroupV2.InvitationCollectedData invitationCollectedData; private final boolean propagationNeeded; + private final boolean repingAllGroupMembers; @SuppressWarnings("unused") @@ -3047,6 +3070,7 @@ public InitiateBlobReDownloadStep(InitialProtocolState startState, GroupReDownlo this.dialogUuid = UUID.randomUUID(); this.invitationCollectedData = null; this.propagationNeeded = true; + this.repingAllGroupMembers = true; } @SuppressWarnings("unused") @@ -3057,6 +3081,7 @@ public InitiateBlobReDownloadStep(InitialProtocolState startState, InvitationRej this.dialogUuid = UUID.randomUUID(); this.invitationCollectedData = null; this.propagationNeeded = true; + this.repingAllGroupMembers = false; } @SuppressWarnings("unused") @@ -3067,6 +3092,7 @@ public InitiateBlobReDownloadStep(InitialProtocolState startState, PropagateInvi this.dialogUuid = UUID.randomUUID(); this.invitationCollectedData = null; this.propagationNeeded = false; + this.repingAllGroupMembers = false; } @SuppressWarnings("unused") @@ -3078,6 +3104,7 @@ public InitiateBlobReDownloadStep(InvitationReceivedState startState, Invitation this.invitationCollectedData = new GroupV2.InvitationCollectedData(); this.invitationCollectedData.addBlobKeysCandidates(startState.inviterIdentity, startState.blobKeys); this.propagationNeeded = true; + this.repingAllGroupMembers = false; } @SuppressWarnings("unused") @@ -3089,6 +3116,7 @@ public InitiateBlobReDownloadStep(InvitationReceivedState startState, PropagateI this.invitationCollectedData = new GroupV2.InvitationCollectedData(); this.invitationCollectedData.addBlobKeysCandidates(startState.inviterIdentity, startState.blobKeys); this.propagationNeeded = false; + this.repingAllGroupMembers = false; } @@ -3129,6 +3157,31 @@ public ConcreteProtocolState executeStep() throws Exception { } } + if (repingAllGroupMembers) { + try { + // do not fail the step if sending the pings fails + byte[] ownGroupInvitationNonce = protocolManagerSession.identityDelegate.getGroupV2OwnGroupInvitationNonce(protocolManagerSession.session, getOwnedIdentity(), groupIdentifier); + if (ownGroupInvitationNonce != null) { + for (GroupV2.IdentityAndPermissions groupMember : protocolManagerSession.identityDelegate.getGroupV2OtherMembersAndPermissions(protocolManagerSession.session, getOwnedIdentity(), groupIdentifier)) { + byte[] pingSignature = protocolManagerSession.identityDelegate.signGroupInvitationNonce( + protocolManagerSession.session, + Constants.SignatureContext.GROUP_JOIN_NONCE, + groupIdentifier, + ownGroupInvitationNonce, + groupMember.identity, + getOwnedIdentity(), + getPrng()); + + CoreProtocolMessage coreProtocolMessage = buildCoreProtocolMessage(SendChannelInfo.createAsymmetricBroadcastChannelInfo(groupMember.identity, getOwnedIdentity())); + ChannelMessageToSend messageToSend = new PingMessage(coreProtocolMessage, groupIdentifier, ownGroupInvitationNonce, pingSignature, false).generateChannelProtocolMessageToSend(); + protocolManagerSession.channelDelegate.post(protocolManagerSession.session, messageToSend, getPrng()); + } + } + } catch (Exception e) { + e.printStackTrace(); + } + } + protocolManagerSession.identityDelegate.freezeGroupV2(protocolManagerSession.session, getOwnedIdentity(), groupIdentifier); byte[] serverQueryNonce = getPrng().bytes(16); diff --git a/obv_messenger/app/build.gradle b/obv_messenger/app/build.gradle index c35c1948..70b7ffe0 100644 --- a/obv_messenger/app/build.gradle +++ b/obv_messenger/app/build.gradle @@ -16,8 +16,8 @@ android { applicationId "io.olvid.messenger" minSdkVersion 21 targetSdk 33 - versionCode 201 - versionName "0.14.0" + versionCode 202 + versionName "0.14.1" vectorDrawables.useSupportLibrary true multiDexEnabled true resConfigs 'en', 'fr' @@ -119,9 +119,9 @@ dependencies { implementation project(':engine') - implementation 'com.google.android.material:material:1.8.0' + implementation 'com.google.android.material:material:1.9.0' - implementation 'androidx.core:core-ktx:1.9.0' + implementation 'androidx.core:core-ktx:1.10.1' def composeBom = platform 'androidx.compose:compose-bom:2023.03.00' implementation composeBom implementation 'androidx.compose.material:material' @@ -144,16 +144,16 @@ dependencies { implementation 'androidx.appcompat:appcompat:1.6.1' implementation 'androidx.emoji2:emoji2:1.3.0' implementation 'androidx.emoji2:emoji2-bundled:1.3.0' - implementation 'androidx.activity:activity:1.7.0' + implementation 'androidx.activity:activity:1.7.1' implementation 'androidx.biometric:biometric:1.1.0' implementation 'androidx.camera:camera-camera2:1.2.2' implementation 'androidx.camera:camera-lifecycle:1.2.2' implementation 'androidx.camera:camera-view:1.2.2' implementation 'androidx.constraintlayout:constraintlayout:2.1.4' - implementation 'androidx.core:core-splashscreen:1.0.0' - implementation 'androidx.core:core:1.9.0' + implementation 'androidx.core:core-splashscreen:1.0.1' + implementation 'androidx.core:core:1.10.1' implementation 'androidx.exifinterface:exifinterface:1.3.6' - implementation 'androidx.fragment:fragment:1.5.6' + implementation 'androidx.fragment:fragment:1.5.7' implementation 'androidx.media2:media2-player:1.2.1' implementation 'androidx.media2:media2-session:1.2.1' implementation 'androidx.media2:media2-widget:1.2.1' @@ -168,7 +168,7 @@ dependencies { implementation 'androidx.work:work-runtime:2.8.1' implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-android:1.6.4' - implementation 'org.jsoup:jsoup:1.15.4' + implementation 'org.jsoup:jsoup:1.16.1' // webclient implementation 'com.google.protobuf:protobuf-lite:3.0.1' @@ -178,8 +178,7 @@ dependencies { implementation 'org.bitbucket.b_c:jose4j:0.9.3' // map libre integration - // WARNING: our code is not compatible with maplibre 10 - implementation 'org.maplibre.gl:android-sdk:10.0.2' + implementation 'org.maplibre.gl:android-sdk:10.2.0' implementation 'org.maplibre.gl:android-plugin-annotation-v9:1.0.0' /////////// @@ -203,7 +202,7 @@ dependencies { // Google Drive fullImplementation 'com.google.android.gms:play-services-auth:20.5.0' - fullImplementation('com.google.http-client:google-http-client-gson:1.43.1') { + fullImplementation('com.google.http-client:google-http-client-gson:1.43.2') { exclude group: 'org.apache.httpcomponents' } fullImplementation('com.google.api-client:google-api-client-android:2.2.0') { @@ -214,7 +213,7 @@ dependencies { } // opensource license page - fullImplementation 'com.google.android.gms:play-services-oss-licenses:17.0.0' + fullImplementation 'com.google.android.gms:play-services-oss-licenses:17.0.1' // ML kit QR-code scanning fullImplementation 'com.google.mlkit:barcode-scanning:17.1.0' diff --git a/obv_messenger/app/src/main/java/io/olvid/messenger/App.java b/obv_messenger/app/src/main/java/io/olvid/messenger/App.java index 63d17729..589ee318 100644 --- a/obv_messenger/app/src/main/java/io/olvid/messenger/App.java +++ b/obv_messenger/app/src/main/java/io/olvid/messenger/App.java @@ -84,9 +84,9 @@ import io.olvid.engine.Logger; import io.olvid.engine.engine.types.EngineAPI; import io.olvid.messenger.activities.ContactDetailsActivity; -import io.olvid.messenger.activities.GroupV2DetailsActivity; import io.olvid.messenger.activities.GroupCreationActivity; import io.olvid.messenger.activities.GroupDetailsActivity; +import io.olvid.messenger.activities.GroupV2DetailsActivity; import io.olvid.messenger.activities.LockScreenActivity; import io.olvid.messenger.activities.MessageDetailsActivity; import io.olvid.messenger.activities.OwnedIdentityDetailsActivity; diff --git a/obv_messenger/app/src/main/java/io/olvid/messenger/EngineNotificationProcessor.java b/obv_messenger/app/src/main/java/io/olvid/messenger/EngineNotificationProcessor.java index 4d6138b9..1cc58a84 100644 --- a/obv_messenger/app/src/main/java/io/olvid/messenger/EngineNotificationProcessor.java +++ b/obv_messenger/app/src/main/java/io/olvid/messenger/EngineNotificationProcessor.java @@ -19,6 +19,10 @@ package io.olvid.messenger; +import android.content.Context; +import android.content.RestrictionsManager; +import android.os.Bundle; + import java.util.Arrays; import java.util.HashMap; import java.util.List; @@ -138,6 +142,21 @@ public void onUploadFailure(int error) { boolean updated = (boolean) userInfo.get(EngineNotifications.WELL_KNOWN_DOWNLOAD_SUCCESS_UPDATED_KEY); if (appInfo != null) { + try { + RestrictionsManager restrictionsManager = (RestrictionsManager) App.getContext().getSystemService(Context.RESTRICTIONS_SERVICE); + Bundle restrictions = restrictionsManager.getApplicationRestrictions(); + + if (restrictions != null && restrictions.containsKey("disable_new_version_notification")) { + boolean disableNewVersionNotification = restrictions.getBoolean("disable_new_version_notification"); + if (disableNewVersionNotification) { + // if notifications are disable, do not even check if our version is up-to-date + break; + } + } + } catch (Exception e) { + e.printStackTrace(); + } + if (updated) { Integer latest = appInfo.get("latest_android"); if (latest != null && latest > BuildConfig.VERSION_CODE) { diff --git a/obv_messenger/app/src/main/java/io/olvid/messenger/databases/dao/DiscussionDao.java b/obv_messenger/app/src/main/java/io/olvid/messenger/databases/dao/DiscussionDao.java index 18427b4a..8c5539f8 100644 --- a/obv_messenger/app/src/main/java/io/olvid/messenger/databases/dao/DiscussionDao.java +++ b/obv_messenger/app/src/main/java/io/olvid/messenger/databases/dao/DiscussionDao.java @@ -312,7 +312,7 @@ public abstract class DiscussionDao { public abstract LiveData> getLatestDiscussionsInWhichYouWrote(); @Query("SELECT " + PREFIX_DISCUSSION_COLUMNS + ", " + - " CASE WHEN grp." + Group.GROUP_MEMBERS_NAMES + " IS NULL THEN grpp." + Group2.GROUP_MEMBERS_NAMES + " ELSE grp." + Group.GROUP_MEMBERS_NAMES + " END AS groupMemberNames" + + " COALESCE(grp." + Group.GROUP_MEMBERS_NAMES + ", grpp." + Group2.GROUP_MEMBERS_NAMES + ") AS groupMemberNames " + " FROM " + Discussion.TABLE_NAME + " AS disc " + " LEFT JOIN " + Group.TABLE_NAME + " AS grp " + " ON disc." + Discussion.BYTES_DISCUSSION_IDENTIFIER + " = grp." + Group.BYTES_GROUP_OWNER_AND_UID + @@ -353,10 +353,15 @@ public abstract class DiscussionDao { " WHERE disc.id = :discussionId ") public abstract LiveData getWithGroupMembersCount(long discussionId); - @SuppressWarnings(RoomWarnings.CURSOR_MISMATCH) // the column is_group is used for sorting only + @SuppressWarnings(RoomWarnings.CURSOR_MISMATCH) // the columns is_group and status are used for sorting only @Query("SELECT " + PREFIX_DISCUSSION_COLUMNS + ", " + - " CASE WHEN grp." + Group.GROUP_MEMBERS_NAMES + " IS NULL THEN grpp." + Group2.GROUP_MEMBERS_NAMES + " ELSE grp." + Group.GROUP_MEMBERS_NAMES + " END AS groupMemberNames, " + - " CASE WHEN disc." + Discussion.DISCUSSION_TYPE + " != " + Discussion.TYPE_CONTACT + " THEN 1 ELSE 0 END AS is_group " + + " COALESCE(grp." + Group.GROUP_MEMBERS_NAMES + ", grpp." + Group2.GROUP_MEMBERS_NAMES + ") AS groupMemberNames, " + + " CASE WHEN disc." + Discussion.DISCUSSION_TYPE + " != " + Discussion.TYPE_CONTACT + " THEN 1 ELSE 0 END AS is_group, " + + " CASE disc." + Discussion.STATUS + + " WHEN " + Discussion.STATUS_NORMAL + " THEN 0 " + + " WHEN " + Discussion.STATUS_PRE_DISCUSSION + " THEN 1 " + + " ELSE 2 " + + " END AS status " + " FROM " + Discussion.TABLE_NAME + " AS disc " + " LEFT JOIN " + Group.TABLE_NAME + " AS grp " + " ON disc." + Discussion.BYTES_DISCUSSION_IDENTIFIER + " = grp." + Group.BYTES_GROUP_OWNER_AND_UID + @@ -367,13 +372,18 @@ public abstract class DiscussionDao { " AND disc." + Discussion.BYTES_OWNED_IDENTITY + " = grpp." + Group2.BYTES_OWNED_IDENTITY + " AND disc." + Discussion.DISCUSSION_TYPE + " = " + Discussion.TYPE_GROUP_V2 + " WHERE disc." + Discussion.BYTES_OWNED_IDENTITY + " = :ownedIdentityBytes " + - " ORDER BY is_group, disc." + Discussion.TITLE + " COLLATE NOCASE ASC") + " ORDER BY status, is_group, disc." + Discussion.TITLE + " COLLATE NOCASE ASC") public abstract LiveData> getAllWithGroupMembersNames(byte[] ownedIdentityBytes); - @SuppressWarnings(RoomWarnings.CURSOR_MISMATCH) // the column is_group is used for sorting only + @SuppressWarnings(RoomWarnings.CURSOR_MISMATCH) // the columns is_group and status are used for sorting only @Query("SELECT " + PREFIX_DISCUSSION_COLUMNS + ", " + - " CASE WHEN grp." + Group.GROUP_MEMBERS_NAMES + " IS NULL THEN grpp." + Group2.GROUP_MEMBERS_NAMES + " ELSE grp." + Group.GROUP_MEMBERS_NAMES + " END AS groupMemberNames, " + - " CASE WHEN disc." + Discussion.DISCUSSION_TYPE + " != " + Discussion.TYPE_CONTACT + " THEN 1 ELSE 0 END AS is_group " + + " COALESCE(grp." + Group.GROUP_MEMBERS_NAMES + ", grpp." + Group2.GROUP_MEMBERS_NAMES + ") AS groupMemberNames, " + + " CASE WHEN disc." + Discussion.DISCUSSION_TYPE + " != " + Discussion.TYPE_CONTACT + " THEN 1 ELSE 0 END AS is_group, " + + " CASE disc." + Discussion.STATUS + + " WHEN " + Discussion.STATUS_NORMAL + " THEN 0 " + + " WHEN " + Discussion.STATUS_PRE_DISCUSSION + " THEN 1 " + + " ELSE 2 " + + " END AS status " + " FROM " + Discussion.TABLE_NAME + " AS disc " + " LEFT JOIN " + Group.TABLE_NAME + " AS grp " + " ON disc." + Discussion.BYTES_DISCUSSION_IDENTIFIER + " = grp." + Group.BYTES_GROUP_OWNER_AND_UID + @@ -384,12 +394,12 @@ public abstract class DiscussionDao { " AND disc." + Discussion.BYTES_OWNED_IDENTITY + " = grpp." + Group2.BYTES_OWNED_IDENTITY + " AND disc." + Discussion.DISCUSSION_TYPE + " = " + Discussion.TYPE_GROUP_V2 + " WHERE disc." + Discussion.BYTES_OWNED_IDENTITY + " = :ownedIdentityBytes " + - " ORDER BY disc." + Discussion.PINNED + " DESC, is_group, disc." + Discussion.TITLE + " COLLATE NOCASE ASC") + " ORDER BY disc." + Discussion.PINNED + " DESC, status, is_group, disc." + Discussion.TITLE + " COLLATE NOCASE ASC") public abstract LiveData> getAllPinnedFirstWithGroupMembersNames(byte[] ownedIdentityBytes); @SuppressWarnings(RoomWarnings.CURSOR_MISMATCH) // the column is_group is used for sorting only @Query("SELECT " + PREFIX_DISCUSSION_COLUMNS + ", " + - " CASE WHEN grp." + Group.GROUP_MEMBERS_NAMES + " IS NULL THEN grpp." + Group2.GROUP_MEMBERS_NAMES + " ELSE grp." + Group.GROUP_MEMBERS_NAMES + " END AS groupMemberNames, " + + " COALESCE(grp." + Group.GROUP_MEMBERS_NAMES + ", grpp." + Group2.GROUP_MEMBERS_NAMES + ") AS groupMemberNames, " + " CASE WHEN disc." + Discussion.DISCUSSION_TYPE + " != " + Discussion.TYPE_CONTACT + " THEN 1 ELSE 0 END AS is_group " + " FROM " + Discussion.TABLE_NAME + " AS disc " + " LEFT JOIN " + Group.TABLE_NAME + " AS grp " + @@ -406,7 +416,7 @@ public abstract class DiscussionDao { public abstract LiveData> getAllNotLockedWithGroupMembersNames(byte[] ownedIdentityBytes); @Query("SELECT " + PREFIX_DISCUSSION_COLUMNS + ", " + - " CASE WHEN grp." + Group.GROUP_MEMBERS_NAMES + " IS NULL THEN grpp." + Group2.GROUP_MEMBERS_NAMES + " ELSE grp." + Group.GROUP_MEMBERS_NAMES + " END AS groupMemberNames " + + " COALESCE(grp." + Group.GROUP_MEMBERS_NAMES + ", grpp." + Group2.GROUP_MEMBERS_NAMES + ") AS groupMemberNames " + " FROM " + Discussion.TABLE_NAME + " AS disc " + " LEFT JOIN " + Group.TABLE_NAME + " AS grp " + " ON disc." + Discussion.BYTES_DISCUSSION_IDENTIFIER + " = grp." + Group.BYTES_GROUP_OWNER_AND_UID + @@ -422,7 +432,7 @@ public abstract class DiscussionDao { public abstract LiveData> getAllNotLockedWithGroupMembersNamesOrderedByActivity(byte[] ownedIdentityBytes); @Query("SELECT " + PREFIX_DISCUSSION_COLUMNS + ", " + - " CASE WHEN grp." + Group.GROUP_MEMBERS_NAMES + " IS NULL THEN grpp." + Group2.GROUP_MEMBERS_NAMES + " ELSE grp." + Group.GROUP_MEMBERS_NAMES + " END AS groupMemberNames " + + " COALESCE(grp." + Group.GROUP_MEMBERS_NAMES + ", grpp." + Group2.GROUP_MEMBERS_NAMES + ") AS groupMemberNames " + " FROM " + Discussion.TABLE_NAME + " AS disc " + " INNER JOIN ( SELECT " + ContactGroupJoin.BYTES_GROUP_OWNER_AND_UID + " AS gid, " + Discussion.TYPE_GROUP + " AS dt FROM " + ContactGroupJoin.TABLE_NAME + " WHERE " + ContactGroupJoin.BYTES_CONTACT_IDENTITY + " = :bytesContactIdentity " + diff --git a/obv_messenger/app/src/main/java/io/olvid/messenger/databases/entity/Contact.java b/obv_messenger/app/src/main/java/io/olvid/messenger/databases/entity/Contact.java index f7fd80ce..7631fad5 100644 --- a/obv_messenger/app/src/main/java/io/olvid/messenger/databases/entity/Contact.java +++ b/obv_messenger/app/src/main/java/io/olvid/messenger/databases/entity/Contact.java @@ -371,7 +371,9 @@ public static Contact createFakeFromOwnedIdentity(@NonNull OwnedIdentity ownedId return null; } else { byte[] sortDisplayName = ContactDisplayNameFormatChangedTask.computeSortDisplayName(ownIdentityDetails, ownedIdentity.customDisplayName, SettingsActivity.getSortContactsByLastName()); - String fullSearchDisplayName = StringUtils.unAccent(ownIdentityDetails.formatDisplayName(JsonIdentityDetails.FORMAT_STRING_FOR_SEARCH, false)); + String fullSearchDisplayName = ownedIdentity.customDisplayName == null ? + StringUtils.unAccent(ownIdentityDetails.formatDisplayName(JsonIdentityDetails.FORMAT_STRING_FOR_SEARCH, false)) : + StringUtils.unAccent(ownedIdentity.customDisplayName + " " + ownIdentityDetails.formatDisplayName(JsonIdentityDetails.FORMAT_STRING_FOR_SEARCH, false)); return new Contact(ownedIdentity.bytesOwnedIdentity, ownedIdentity.bytesOwnedIdentity, ownedIdentity.customDisplayName, diff --git a/obv_messenger/app/src/main/java/io/olvid/messenger/databases/entity/Discussion.java b/obv_messenger/app/src/main/java/io/olvid/messenger/databases/entity/Discussion.java index 78b98d93..37c423ee 100644 --- a/obv_messenger/app/src/main/java/io/olvid/messenger/databases/entity/Discussion.java +++ b/obv_messenger/app/src/main/java/io/olvid/messenger/databases/entity/Discussion.java @@ -74,7 +74,7 @@ public class Discussion { public static final String UNREAD = "unread"; // specify if discussion as been manually marked as unread public static final String ACTIVE = "active"; public static final String TRUST_LEVEL = "trust_level"; - public static final String STATUS = "status"; // normal, locked, (pre-discussion?) + public static final String STATUS = "status"; // normal, locked, or pre-discussion public static final int TYPE_CONTACT = 1; public static final int TYPE_GROUP = 2; diff --git a/obv_messenger/app/src/main/java/io/olvid/messenger/discussion/NewMessagesItemDecoration.java b/obv_messenger/app/src/main/java/io/olvid/messenger/discussion/NewMessagesItemDecoration.java index bfad408d..84f9c7a7 100644 --- a/obv_messenger/app/src/main/java/io/olvid/messenger/discussion/NewMessagesItemDecoration.java +++ b/obv_messenger/app/src/main/java/io/olvid/messenger/discussion/NewMessagesItemDecoration.java @@ -81,7 +81,7 @@ public void onDraw(@NonNull Canvas canvas, @NonNull RecyclerView parent, @NonNul continue; } int position = parent.getChildViewHolder(child).getBindingAdapterPosition(); - if (position == RecyclerView.NO_POSITION || position == 0 || position > messageListAdapter.messages.size()) { + if (position == RecyclerView.NO_POSITION || position == 0 || messageListAdapter.messages == null || position > messageListAdapter.messages.size()) { continue; } position--; diff --git a/obv_messenger/app/src/main/java/io/olvid/messenger/discussion/location/MapViewMapLibreFragment.java b/obv_messenger/app/src/main/java/io/olvid/messenger/discussion/location/MapViewMapLibreFragment.java index 82f06440..e7ef6a23 100644 --- a/obv_messenger/app/src/main/java/io/olvid/messenger/discussion/location/MapViewMapLibreFragment.java +++ b/obv_messenger/app/src/main/java/io/olvid/messenger/discussion/location/MapViewMapLibreFragment.java @@ -272,9 +272,10 @@ public void centerOnCurrentLocation(boolean animate) { } // if lastKnownLocation is accessible use it to center - if (mapboxMap.getLocationComponent().isLocationComponentEnabled() && mapboxMap.getLocationComponent().getLastKnownLocation() != null) { - centerOnLocation(mapboxMap.getLocationComponent().getLastKnownLocation(), animate); - mapboxMap.getLocationComponent().forceLocationUpdate(mapboxMap.getLocationComponent().getLastKnownLocation()); + Location lastKnownLocation = mapboxMap.getLocationComponent().getLastKnownLocation(); + if (mapboxMap.getLocationComponent().isLocationComponentEnabled() && lastKnownLocation != null) { + centerOnLocation(lastKnownLocation, animate); + mapboxMap.getLocationComponent().forceLocationUpdate(lastKnownLocation); } else { // else try to get best provider last location, and else request current location (can be quite long) LocationManager locationManager = (LocationManager) activity.getSystemService(Context.LOCATION_SERVICE); @@ -291,8 +292,10 @@ public void centerOnCurrentLocation(boolean animate) { Executor executor = Build.VERSION.SDK_INT >= Build.VERSION_CODES.R ? App.getContext().getMainExecutor() : new HandlerExecutor(Looper.getMainLooper()); if (provider != null) { LocationManagerCompat.getCurrentLocation(locationManager, provider, null, executor, location -> { - centerOnLocation(location, animate); - mapboxMap.getLocationComponent().forceLocationUpdate(location); + if (location != null) { + centerOnLocation(location, animate); + mapboxMap.getLocationComponent().forceLocationUpdate(location); + } }); } } @@ -332,7 +335,7 @@ public void launchMapSnapshot(@NonNull Consumer onSnapshotReadyCallback) onSnapshotReadyCallback.accept(null); return; } - // hide attributions icon + // hide attributions icon7 mapboxMap.getUiSettings().setAttributionEnabled(false); mapboxMap.getUiSettings().setCompassEnabled(false); diff --git a/obv_messenger/app/src/main/java/io/olvid/messenger/main/calls/CallLogItem.kt b/obv_messenger/app/src/main/java/io/olvid/messenger/main/calls/CallLogItem.kt index b7bee213..fb3ff204 100644 --- a/obv_messenger/app/src/main/java/io/olvid/messenger/main/calls/CallLogItem.kt +++ b/obv_messenger/app/src/main/java/io/olvid/messenger/main/calls/CallLogItem.kt @@ -35,6 +35,8 @@ import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.requiredSize import androidx.compose.foundation.layout.requiredWidth import androidx.compose.foundation.layout.size +import androidx.compose.foundation.layout.width +import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.material.DropdownMenu import androidx.compose.material.DropdownMenuItem import androidx.compose.material.Text @@ -46,6 +48,7 @@ import androidx.compose.runtime.setValue import androidx.compose.ui.Alignment.Companion.BottomCenter import androidx.compose.ui.Alignment.Companion.CenterVertically import androidx.compose.ui.Modifier +import androidx.compose.ui.draw.clip import androidx.compose.ui.res.colorResource import androidx.compose.ui.res.painterResource import androidx.compose.ui.res.stringResource @@ -96,7 +99,7 @@ fun CallLogItemView( modifier = Modifier .padding( horizontal = 16.dp, - vertical = 4.dp, + vertical = 8.dp, ) .requiredSize(40.dp), initialViewSetup = initialViewSetup, @@ -138,13 +141,15 @@ fun CallLogItemView( Image( modifier = Modifier + .clip(shape = RoundedCornerShape(size = 36.dp)) .clickable { onClick.invoke() } .padding(8.dp) - .size(40.dp), + .size(32.dp), painter = painterResource(id = R.drawable.ic_phone_grey), contentDescription = stringResource(id = R.string.button_label_call) ) + Spacer(modifier = Modifier.width(4.dp)) } } } diff --git a/obv_messenger/app/src/main/java/io/olvid/messenger/main/calls/CallLogScreen.kt b/obv_messenger/app/src/main/java/io/olvid/messenger/main/calls/CallLogScreen.kt index 6be61d65..5f860a52 100644 --- a/obv_messenger/app/src/main/java/io/olvid/messenger/main/calls/CallLogScreen.kt +++ b/obv_messenger/app/src/main/java/io/olvid/messenger/main/calls/CallLogScreen.kt @@ -60,15 +60,6 @@ fun CallLogScreen( modifier = Modifier .fillMaxSize() ) { - FloatingActionButton(modifier = Modifier - .align(Alignment.BottomEnd) - .padding(bottom = 80.dp, end = 16.dp), - onClick = onNewCallClick - ) { - Image(painter = painterResource(id = R.drawable.ic_phone), contentDescription = stringResource( - id = R.string.button_label_call - )) - } callLog?.let { log -> if (log.isEmpty().not()) { LazyColumn( @@ -111,6 +102,15 @@ fun CallLogScreen( EmptyListCard(stringRes = R.string.explanation_empty_call_log) } } + FloatingActionButton(modifier = Modifier + .align(Alignment.BottomEnd) + .padding(bottom = 80.dp, end = 16.dp), + onClick = onNewCallClick + ) { + Image(painter = painterResource(id = R.drawable.ic_phone), contentDescription = stringResource( + id = R.string.button_label_call + )) + } } } } \ No newline at end of file diff --git a/obv_messenger/app/src/main/java/io/olvid/messenger/main/calls/CallLogViewModel.kt b/obv_messenger/app/src/main/java/io/olvid/messenger/main/calls/CallLogViewModel.kt index 18f57a35..79f338b4 100644 --- a/obv_messenger/app/src/main/java/io/olvid/messenger/main/calls/CallLogViewModel.kt +++ b/obv_messenger/app/src/main/java/io/olvid/messenger/main/calls/CallLogViewModel.kt @@ -34,6 +34,7 @@ import io.olvid.messenger.databases.AppDatabase import io.olvid.messenger.databases.dao.CallLogItemDao.CallLogItemAndContacts import io.olvid.messenger.databases.entity.CallLogItem import io.olvid.messenger.databases.entity.OwnedIdentity +import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.launch class CallLogViewModel : ViewModel() { @@ -78,7 +79,7 @@ class CallLogViewModel : ViewModel() { } fun delete(callLogItem: CallLogItem) { - viewModelScope.launch { + viewModelScope.launch(Dispatchers.IO) { AppDatabase.getInstance().callLogItemDao().delete(callLogItem) } } diff --git a/obv_messenger/app/src/main/java/io/olvid/messenger/main/contacts/ContactListFragment.kt b/obv_messenger/app/src/main/java/io/olvid/messenger/main/contacts/ContactListFragment.kt index cb0caacf..a42ae54b 100644 --- a/obv_messenger/app/src/main/java/io/olvid/messenger/main/contacts/ContactListFragment.kt +++ b/obv_messenger/app/src/main/java/io/olvid/messenger/main/contacts/ContactListFragment.kt @@ -135,8 +135,8 @@ class ContactListFragment : RefreshingFragment(), ContactMenu { ownedIdentity.bytesOwnedIdentity, contactOrKeycloakDetails.keycloakUserDetails.id, contactOrKeycloakDetails.keycloakUserDetails.identity, - object : KeycloakCallback { - override fun success(result: Void) { + object : KeycloakCallback { + override fun success(result: Void?) { App.toast( getString( R.string.toast_message_contact_added, diff --git a/obv_messenger/app/src/main/java/io/olvid/messenger/main/contacts/ContactListViewModel.kt b/obv_messenger/app/src/main/java/io/olvid/messenger/main/contacts/ContactListViewModel.kt index 83c33f9f..ca427be7 100644 --- a/obv_messenger/app/src/main/java/io/olvid/messenger/main/contacts/ContactListViewModel.kt +++ b/obv_messenger/app/src/main/java/io/olvid/messenger/main/contacts/ContactListViewModel.kt @@ -32,6 +32,7 @@ import io.olvid.engine.engine.types.JsonKeycloakUserDetails import io.olvid.messenger.AppSingleton import io.olvid.messenger.customClasses.StringUtils import io.olvid.messenger.databases.entity.Contact +import io.olvid.messenger.databases.entity.OwnedIdentity import io.olvid.messenger.main.contacts.ContactListViewModel.ContactOrKeycloakDetails import io.olvid.messenger.main.contacts.ContactListViewModel.ContactType.CONTACT import io.olvid.messenger.main.contacts.ContactListViewModel.ContactType.KEYCLOAK @@ -106,6 +107,7 @@ class ContactListViewModel : ViewModel() { filteredContacts, unfilteredContacts, unfilteredNotOneToOneContacts, + keycloakSearchBytesOwnedIdentity, keycloakSearchInProgress, keycloakSearchResults, keycloakSearchAdditionalResults @@ -127,6 +129,7 @@ class ContactListViewModel : ViewModel() { filteredContacts: MutableLiveData?>, unfilteredContacts: List?, unfilteredNotOneToOneContacts: List?, + keycloakSearchBytesOwnedIdentity: ByteArray?, keycloakSearchInProgress: Boolean, keycloakSearchResults: List?, keycloakSearchAdditionalResults: Boolean @@ -135,6 +138,7 @@ class ContactListViewModel : ViewModel() { private val filteredContacts: MutableLiveData?> private val unfilteredContacts: List? private val unfilteredNotOneToOneContacts: List? + private val keycloakSearchBytesOwnedIdentity: ByteArray? private val keycloakSearchInProgress: Boolean private val keycloakSearchResults: List? private val keycloakSearchAdditionalResults: Boolean @@ -143,6 +147,7 @@ class ContactListViewModel : ViewModel() { this.filteredContacts = filteredContacts this.unfilteredContacts = unfilteredContacts this.unfilteredNotOneToOneContacts = unfilteredNotOneToOneContacts + this.keycloakSearchBytesOwnedIdentity = keycloakSearchBytesOwnedIdentity this.keycloakSearchInProgress = keycloakSearchInProgress this.keycloakSearchResults = keycloakSearchResults this.keycloakSearchAdditionalResults = keycloakSearchAdditionalResults @@ -201,9 +206,8 @@ class ContactListViewModel : ViewModel() { keycloakSearchResults?.let { for (keycloakUserDetails in keycloakSearchResults) { // check if the we know the contact by querying the cache (note that this also filters out our ownedIdentity) - val displayName = - AppSingleton.getContactCustomDisplayName(keycloakUserDetails.identity) - if (displayName == null && keycloakUserDetails.identity != null) { + val trustLevel : Int? = AppSingleton.getContactTrustLevel(keycloakUserDetails.identity) + if (trustLevel == null && keycloakUserDetails.identity != null && !(keycloakUserDetails.identity contentEquals keycloakSearchBytesOwnedIdentity)) { // unknown contact --> add them to the list list.add(ContactOrKeycloakDetails(keycloakUserDetails)) } diff --git a/obv_messenger/app/src/main/java/io/olvid/messenger/notifications/AndroidNotificationManager.java b/obv_messenger/app/src/main/java/io/olvid/messenger/notifications/AndroidNotificationManager.java index 2b43d6df..6d60793e 100644 --- a/obv_messenger/app/src/main/java/io/olvid/messenger/notifications/AndroidNotificationManager.java +++ b/obv_messenger/app/src/main/java/io/olvid/messenger/notifications/AndroidNotificationManager.java @@ -698,7 +698,11 @@ public static void displayReceivedMessageNotification(@NonNull Discussion discus int notificationId = getMessageNotificationId(discussion.id); - notificationManager.notify(notificationId, builder.build()); + try { + notificationManager.notify(notificationId, builder.build()); + } catch (Exception e) { + e.printStackTrace(); + } if (contact != null) { if (messageLastVibrationTimestamp.containsKey(notificationId)) { Long timestamp = messageLastVibrationTimestamp.get(notificationId); diff --git a/obv_messenger/app/src/main/java/io/olvid/messenger/services/MediaPlayerService.java b/obv_messenger/app/src/main/java/io/olvid/messenger/services/MediaPlayerService.java index cd98d3dc..1c2b0e96 100644 --- a/obv_messenger/app/src/main/java/io/olvid/messenger/services/MediaPlayerService.java +++ b/obv_messenger/app/src/main/java/io/olvid/messenger/services/MediaPlayerService.java @@ -257,7 +257,11 @@ private void internalStartForeground(boolean paused) { } builder.setDeleteIntent(stopPendingIntent); - startForeground(SERVICE_ID, builder.build()); + try { + startForeground(SERVICE_ID, builder.build()); + } catch (Exception e) { + e.printStackTrace(); + } } public void seekMedia(long timeMs) { diff --git a/obv_messenger/app/src/main/java/io/olvid/messenger/services/UnifiedForegroundService.java b/obv_messenger/app/src/main/java/io/olvid/messenger/services/UnifiedForegroundService.java index 12e7ad69..64d6338e 100644 --- a/obv_messenger/app/src/main/java/io/olvid/messenger/services/UnifiedForegroundService.java +++ b/obv_messenger/app/src/main/java/io/olvid/messenger/services/UnifiedForegroundService.java @@ -462,7 +462,11 @@ private void stopOrRestartForegroundService() { if (App.isVisible()) { stopForeground(true); } - startForeground(SERVICE_ID, builder.build()); + try { + startForeground(SERVICE_ID, builder.build()); + } catch (Exception e) { + e.printStackTrace(); + } } diff --git a/obv_messenger/app/src/main/java/io/olvid/messenger/settings/SettingsActivity.java b/obv_messenger/app/src/main/java/io/olvid/messenger/settings/SettingsActivity.java index d2fbe97c..27d2348f 100644 --- a/obv_messenger/app/src/main/java/io/olvid/messenger/settings/SettingsActivity.java +++ b/obv_messenger/app/src/main/java/io/olvid/messenger/settings/SettingsActivity.java @@ -1003,7 +1003,8 @@ public static Long getDefaultDiscussionRetentionCount() { if ("".equals(retentionCountString)) { return null; } - return Long.parseLong(retentionCountString); + long count = Long.parseLong(retentionCountString); + return count == 0 ? null : count; } catch (Exception e) { e.printStackTrace(); } @@ -1012,7 +1013,11 @@ public static Long getDefaultDiscussionRetentionCount() { public static void setDefaultDiscussionRetentionCount(long count) { SharedPreferences.Editor editor = PreferenceManager.getDefaultSharedPreferences(App.getContext()).edit(); - editor.putString(PREF_KEY_DEFAULT_DISCUSSION_RETENTION_COUNT, Long.toString(count)); + if (count == 0) { + editor.remove(PREF_KEY_DEFAULT_DISCUSSION_RETENTION_COUNT); + } else { + editor.putString(PREF_KEY_DEFAULT_DISCUSSION_RETENTION_COUNT, Long.toString(count)); + } editor.apply(); } diff --git a/obv_messenger/app/src/main/java/io/olvid/messenger/webrtc/WebrtcCallService.java b/obv_messenger/app/src/main/java/io/olvid/messenger/webrtc/WebrtcCallService.java index b3bb7766..59c3e319 100644 --- a/obv_messenger/app/src/main/java/io/olvid/messenger/webrtc/WebrtcCallService.java +++ b/obv_messenger/app/src/main/java/io/olvid/messenger/webrtc/WebrtcCallService.java @@ -2053,8 +2053,11 @@ private void showOngoingForeground() { .setGroupAlertBehavior(Notification.GROUP_ALERT_SUMMARY) .setCategory(Notification.CATEGORY_CALL) .setContentIntent(callActivityPendingIntent); - - startForeground(SERVICE_ID, builder.build()); + try { + startForeground(SERVICE_ID, builder.build()); + } catch (Exception e) { + e.printStackTrace(); + } } else { NotificationCompat.Builder builder = new NotificationCompat.Builder(this, AndroidNotificationManager.WEBRTC_CALL_SERVICE_NOTIFICATION_CHANNEL_ID); builder.setContentTitle(getString(R.string.notification_title_webrtc_call)) @@ -2069,7 +2072,11 @@ private void showOngoingForeground() { builder.addAction(R.drawable.ic_end_call, getString(R.string.notification_action_end_call), endCallPendingIntent); - startForeground(SERVICE_ID, builder.build()); + try { + startForeground(SERVICE_ID, builder.build()); + } catch (Exception e) { + e.printStackTrace(); + } } } diff --git a/obv_messenger/app/src/main/res/values/strings.xml b/obv_messenger/app/src/main/res/values/strings.xml index 0c7b4440..0da1b178 100644 --- a/obv_messenger/app/src/main/res/values/strings.xml +++ b/obv_messenger/app/src/main/res/values/strings.xml @@ -1057,8 +1057,10 @@ It\'s been more than a week since your last backup. Now is probably a good time for a new one. Keep in mind that an old backup might not contain all your latest contacts.\n\nPress \"setup backups\" to begin. Do you remember your backup key? Having an up to date Olvid backup is essential, but you need your backup key to restore it!\n\nPress \"setup backups\" to verify your key. If you lost it, don\'t worry, you can generate a new one. - Keycloak configuration - Configuration link provided by the Olvid keycloak plugin + Keycloak configuration + Configuration link provided by the Olvid keycloak plugin + Disable new version notification + Set to "true" to prevent users from receiving a notification when a new version of Olvid is available on the store. This is especially usefull if the application can only be updated through the MDM. Open with external app You are about to open a file with an external application. The content of this file will be exposed outside of Olvid.\nDo you wish to proceed? Unblock discussion diff --git a/obv_messenger/app/src/main/res/xml/app_restrictions.xml b/obv_messenger/app/src/main/res/xml/app_restrictions.xml index 02011530..306c825e 100644 --- a/obv_messenger/app/src/main/res/xml/app_restrictions.xml +++ b/obv_messenger/app/src/main/res/xml/app_restrictions.xml @@ -2,8 +2,14 @@ + diff --git a/obv_messenger/build.gradle b/obv_messenger/build.gradle index 72b1786b..31ce9ab6 100644 --- a/obv_messenger/build.gradle +++ b/obv_messenger/build.gradle @@ -6,7 +6,7 @@ buildscript { mavenCentral() } dependencies { - classpath 'com.android.tools.build:gradle:8.0.0' + classpath 'com.android.tools.build:gradle:8.0.1' classpath 'androidx.navigation:navigation-safe-args-gradle-plugin:2.5.3' classpath 'com.google.android.gms:oss-licenses-plugin:0.10.6' diff --git a/obv_messenger/sardine-android/build.gradle b/obv_messenger/sardine-android/build.gradle index c7b11a4d..9514734b 100644 --- a/obv_messenger/sardine-android/build.gradle +++ b/obv_messenger/sardine-android/build.gradle @@ -4,7 +4,7 @@ buildscript { google() } dependencies { - classpath 'com.android.tools.build:gradle:8.0.0' + classpath 'com.android.tools.build:gradle:8.0.1' } }