From 2b7de2a7a6feb2c9ec2c18852b13e500905ea3d2 Mon Sep 17 00:00:00 2001 From: Evgeny Poberezkin <2769109+epoberezkin@users.noreply.github.com> Date: Thu, 7 Jul 2022 19:05:03 +0100 Subject: [PATCH] android: only start service when app is in the background, change service icon (#790) * android: only start service when app is in the background, change service icon * update version v3.0 (38) * set flag --- apps/android/app/build.gradle | 2 +- apps/android/app/src/main/cpp/simplex-api.c | 17 +++++++- .../main/java/chat/simplex/app/SimplexApp.kt | 11 ++--- .../java/chat/simplex/app/SimplexService.kt | 8 ++-- .../java/chat/simplex/app/model/SimpleXAPI.kt | 38 +++++++++++------- .../chat/simplex/app/views/WelcomeView.kt | 1 - .../res/drawable-hdpi/ntf_service_icon.png | Bin 0 -> 1553 bytes .../res/drawable-mdpi/ntf_service_icon.png | Bin 0 -> 1272 bytes .../res/drawable-xhdpi/ntf_service_icon.png | Bin 0 -> 1840 bytes .../res/drawable-xxhdpi/ntf_service_icon.png | Bin 0 -> 2489 bytes .../res/drawable-xxxhdpi/ntf_service_icon.png | Bin 0 -> 2812 bytes .../ios/SimpleX NSE/NotificationService.swift | 1 + 12 files changed, 53 insertions(+), 25 deletions(-) create mode 100644 apps/android/app/src/main/res/drawable-hdpi/ntf_service_icon.png create mode 100644 apps/android/app/src/main/res/drawable-mdpi/ntf_service_icon.png create mode 100644 apps/android/app/src/main/res/drawable-xhdpi/ntf_service_icon.png create mode 100644 apps/android/app/src/main/res/drawable-xxhdpi/ntf_service_icon.png create mode 100644 apps/android/app/src/main/res/drawable-xxxhdpi/ntf_service_icon.png diff --git a/apps/android/app/build.gradle b/apps/android/app/build.gradle index baef53847..9d5670a4e 100644 --- a/apps/android/app/build.gradle +++ b/apps/android/app/build.gradle @@ -11,7 +11,7 @@ android { applicationId "chat.simplex.app" minSdk 29 targetSdk 32 - versionCode 37 + versionCode 38 versionName "3.0" testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" diff --git a/apps/android/app/src/main/cpp/simplex-api.c b/apps/android/app/src/main/cpp/simplex-api.c index e9178df5c..5be1d1fad 100644 --- a/apps/android/app/src/main/cpp/simplex-api.c +++ b/apps/android/app/src/main/cpp/simplex-api.c @@ -24,9 +24,11 @@ Java_chat_simplex_app_SimplexAppKt_initHS(__unused JNIEnv *env, __unused jclass // from simplex-chat typedef void* chat_ctrl; -extern chat_ctrl chat_init(const char * path); +extern chat_ctrl chat_init(const char *path); extern char *chat_send_cmd(chat_ctrl ctrl, const char *cmd); extern char *chat_recv_msg(chat_ctrl ctrl); +extern char *chat_recv_msg_wait(chat_ctrl ctrl, const int wait); +extern char *chat_parse_markdown(const char *str); JNIEXPORT jlong JNICALL Java_chat_simplex_app_SimplexAppKt_chatInit(JNIEnv *env, __unused jclass clazz, jstring datadir) { @@ -48,3 +50,16 @@ JNIEXPORT jstring JNICALL Java_chat_simplex_app_SimplexAppKt_chatRecvMsg(JNIEnv *env, __unused jclass clazz, jlong controller) { return (*env)->NewStringUTF(env, chat_recv_msg((void*)controller)); } + +JNIEXPORT jstring JNICALL +Java_chat_simplex_app_SimplexAppKt_chatRecvMsgWait(JNIEnv *env, __unused jclass clazz, jlong controller, jint wait) { + return (*env)->NewStringUTF(env, chat_recv_msg_wait((void*)controller, wait)); +} + +JNIEXPORT jstring JNICALL +Java_chat_simplex_app_SimplexAppKt_chatParseMarkdown(JNIEnv *env, __unused jclass clazz, jstring str) { + const char *_str = (*env)->GetStringUTFChars(env, str, JNI_FALSE); + jstring res = (*env)->NewStringUTF(env, chat_parse_markdown(_str)); + (*env)->ReleaseStringUTFChars(env, str, _str); + return res; +} diff --git a/apps/android/app/src/main/java/chat/simplex/app/SimplexApp.kt b/apps/android/app/src/main/java/chat/simplex/app/SimplexApp.kt index 73ecd073d..69cae0dd2 100644 --- a/apps/android/app/src/main/java/chat/simplex/app/SimplexApp.kt +++ b/apps/android/app/src/main/java/chat/simplex/app/SimplexApp.kt @@ -24,8 +24,10 @@ external fun pipeStdOutToSocket(socketName: String) : Int // SimpleX API typealias ChatCtrl = Long external fun chatInit(path: String): ChatCtrl -external fun chatSendCmd(ctrl: ChatCtrl, msg: String) : String -external fun chatRecvMsg(ctrl: ChatCtrl) : String +external fun chatSendCmd(ctrl: ChatCtrl, msg: String): String +external fun chatRecvMsg(ctrl: ChatCtrl): String +external fun chatRecvMsgWait(ctrl: ChatCtrl, timeout: Int): String +external fun chatParseMarkdown(str: String): String class SimplexApp: Application(), LifecycleEventObserver { val chatController: ChatController by lazy { @@ -55,7 +57,6 @@ class SimplexApp: Application(), LifecycleEventObserver { chatModel.onboardingStage.value = OnboardingStage.Step1_SimpleXInfo } else { chatController.startChat(user) - SimplexService.start(applicationContext) chatController.showBackgroundServiceNoticeIfNeeded() } } @@ -66,9 +67,9 @@ class SimplexApp: Application(), LifecycleEventObserver { withApi { when (event) { Lifecycle.Event.ON_STOP -> - if (!appPreferences.runServiceInBackground.get()) SimplexService.stop(applicationContext) + if (appPreferences.runServiceInBackground.get()) SimplexService.start(applicationContext) Lifecycle.Event.ON_START -> - SimplexService.start(applicationContext) + SimplexService.stop(applicationContext) Lifecycle.Event.ON_RESUME -> if (chatModel.onboardingStage.value == OnboardingStage.OnboardingComplete) { chatController.showBackgroundServiceNoticeIfNeeded() diff --git a/apps/android/app/src/main/java/chat/simplex/app/SimplexService.kt b/apps/android/app/src/main/java/chat/simplex/app/SimplexService.kt index 94ae6a737..db62727d2 100644 --- a/apps/android/app/src/main/java/chat/simplex/app/SimplexService.kt +++ b/apps/android/app/src/main/java/chat/simplex/app/SimplexService.kt @@ -20,6 +20,7 @@ class SimplexService: Service() { private var wakeLock: PowerManager.WakeLock? = null private var isServiceStarted = false private var isStartingService = false + private var isStoppingService = false private var notificationManager: NotificationManager? = null private var serviceNotification: Notification? = null private val chatController by lazy { (application as SimplexApp).chatController } @@ -71,7 +72,6 @@ class SimplexService: Service() { } else { Log.w(TAG, "Starting foreground service") chatController.startChat(user) - chatController.startReceiver() isServiceStarted = true saveServiceState(self, ServiceState.STARTED) wakeLock = (getSystemService(Context.POWER_SERVICE) as PowerManager).run { @@ -88,6 +88,8 @@ class SimplexService: Service() { private fun stopService() { Log.d(TAG, "Stopping foreground service") + if (!isServiceStarted || isStoppingService) return + isStoppingService = true try { wakeLock?.let { while (it.isHeld) it.release() // release all, in case acquired more than once @@ -98,7 +100,7 @@ class SimplexService: Service() { } catch (e: Exception) { Log.d(TAG, "Service stopped without being started: ${e.message}") } - + isStoppingService = false isServiceStarted = false saveServiceState(this, ServiceState.STOPPED) } @@ -121,7 +123,7 @@ class SimplexService: Service() { PendingIntent.getActivity(this, 0, notificationIntent, PendingIntent.FLAG_IMMUTABLE) } return NotificationCompat.Builder(this, NOTIFICATION_CHANNEL_ID) - .setSmallIcon(R.drawable.ntf_icon) + .setSmallIcon(R.drawable.ntf_service_icon) .setColor(0x88FFFF) .setContentTitle(title) .setContentText(text) diff --git a/apps/android/app/src/main/java/chat/simplex/app/model/SimpleXAPI.kt b/apps/android/app/src/main/java/chat/simplex/app/model/SimpleXAPI.kt index 10e40f30d..598112224 100644 --- a/apps/android/app/src/main/java/chat/simplex/app/model/SimpleXAPI.kt +++ b/apps/android/app/src/main/java/chat/simplex/app/model/SimpleXAPI.kt @@ -117,8 +117,11 @@ class AppPreferences(val context: Context) { } } +private const val MESSAGE_TIMEOUT: Int = 15_000_000 + open class ChatController(private val ctrl: ChatCtrl, val ntfManager: NtfManager, val appContext: Context, val appPrefs: AppPreferences) { val chatModel = ChatModel(this) + private var receiverStarted = false init { chatModel.runServiceInBackground.value = appPrefs.runServiceInBackground.get() @@ -142,6 +145,7 @@ open class ChatController(private val ctrl: ChatCtrl, val ntfManager: NtfManager chatModel.currentUser.value = user chatModel.userCreated.value = true chatModel.onboardingStage.value = OnboardingStage.OnboardingComplete + startReceiver() Log.d(TAG, "chat started") } catch (e: Error) { Log.e(TAG, "failed starting chat $e") @@ -149,8 +153,9 @@ open class ChatController(private val ctrl: ChatCtrl, val ntfManager: NtfManager } } - fun startReceiver() { + private fun startReceiver() { Log.d(TAG, "ChatController startReceiver") + if (receiverStarted) return thread(name="receiver") { GlobalScope.launch { withContext(Dispatchers.IO) { recvMspLoop() } } } @@ -176,18 +181,23 @@ open class ChatController(private val ctrl: ChatCtrl, val ntfManager: NtfManager } } - suspend fun recvMsg(): CR { + private suspend fun recvMsg(): CR? { return withContext(Dispatchers.IO) { - val json = chatRecvMsg(ctrl) - val r = APIResponse.decodeStr(json).resp - Log.d(TAG, "chatRecvMsg: ${r.responseType}") - if (r is CR.Response || r is CR.Invalid) Log.d(TAG, "chatRecvMsg json: $json") - r + val json = chatRecvMsgWait(ctrl, MESSAGE_TIMEOUT) + if (json == "") { + null + } else { + val r = APIResponse.decodeStr(json).resp + Log.d(TAG, "chatRecvMsg: ${r.responseType}") + if (r is CR.Response || r is CR.Invalid) Log.d(TAG, "chatRecvMsg json: $json") + r + } } } - suspend fun recvMspLoop() { - processReceivedMsg(recvMsg()) + private suspend fun recvMspLoop() { + val msg = recvMsg() + if (msg != null) processReceivedMsg(msg) recvMspLoop() } @@ -206,7 +216,7 @@ open class ChatController(private val ctrl: ChatCtrl, val ntfManager: NtfManager throw Error("user not created ${r.responseType} ${r.details}") } - suspend fun apiStartChat(): Boolean { + private suspend fun apiStartChat(): Boolean { val r = sendCmd(CC.StartChat()) when (r) { is CR.ChatStarted -> return true @@ -215,13 +225,13 @@ open class ChatController(private val ctrl: ChatCtrl, val ntfManager: NtfManager } } - suspend fun apiSetFilesFolder(filesFolder: String) { + private suspend fun apiSetFilesFolder(filesFolder: String) { val r = sendCmd(CC.SetFilesFolder(filesFolder)) if (r is CR.CmdOk) return throw Error("failed to set files folder: ${r.responseType} ${r.details}") } - suspend fun apiGetChats(): List { + private suspend fun apiGetChats(): List { val r = sendCmd(CC.ApiGetChats()) if (r is CR.ApiChats ) return r.chats throw Error("failed getting the list of chats: ${r.responseType} ${r.details}") @@ -256,7 +266,7 @@ open class ChatController(private val ctrl: ChatCtrl, val ntfManager: NtfManager return null } - suspend fun getUserSMPServers(): List? { + private suspend fun getUserSMPServers(): List? { val r = sendCmd(CC.GetUserSMPServers()) if (r is CR.UserSMPServers) return r.smpServers Log.e(TAG, "getUserSMPServers bad response: ${r.responseType} ${r.details}") @@ -383,7 +393,7 @@ open class ChatController(private val ctrl: ChatCtrl, val ntfManager: NtfManager return false } - suspend fun apiGetUserAddress(): String? { + private suspend fun apiGetUserAddress(): String? { val r = sendCmd(CC.ShowMyAddress()) if (r is CR.UserContactLink) return r.connReqContact if (r is CR.ChatCmdError && r.chatError is ChatError.ChatErrorStore diff --git a/apps/android/app/src/main/java/chat/simplex/app/views/WelcomeView.kt b/apps/android/app/src/main/java/chat/simplex/app/views/WelcomeView.kt index 833977b98..862e47684 100644 --- a/apps/android/app/src/main/java/chat/simplex/app/views/WelcomeView.kt +++ b/apps/android/app/src/main/java/chat/simplex/app/views/WelcomeView.kt @@ -114,7 +114,6 @@ fun createProfile(chatModel: ChatModel, displayName: String, fullName: String) { Profile(displayName, fullName, null) ) chatModel.controller.startChat(user) - SimplexService.start(chatModel.controller.appContext) chatModel.controller.showBackgroundServiceNoticeIfNeeded() chatModel.onboardingStage.value = OnboardingStage.OnboardingComplete } diff --git a/apps/android/app/src/main/res/drawable-hdpi/ntf_service_icon.png b/apps/android/app/src/main/res/drawable-hdpi/ntf_service_icon.png new file mode 100644 index 0000000000000000000000000000000000000000..2bdab389b1f96ec138e654709ecf2660213ab5f3 GIT binary patch literal 1553 zcmeAS@N?(olHy`uVBq!ia0vp^Dj>|k1|%Oc%$NbBSkfJR9T^xl_H+M9WCijSl0AZa z85pY67#JE_7#My5g&JNkFq9fFFuY1&V6Xz}5igjtE6@fgk&_zXnda-upao=eFt9KR zF)#yJj6lf1D8&FW4aj1!W0Z!o-P$u5SfJv5KpF%*fEc6>LNhI3f~!zjz>Hvnl&)dY z0lJBSv%n*=n1O*?7=#%aX3ddcU|^b*84^(v;p=0SoS&uf-VSw#k=7U$=bf}CY%Ze#KQE)+Ga;hEB z9<8@;8M`+oFo+?&An=1ftYd8;zN-SJBJ;x%fjvCsDvwMv&F#DQ z26Tv*Ui^A>g1N<9*8d0MSQkH7((g9OzgW5E{zdJ^{DYZE!FgI=wtm=I7FRELzwYSD z>ivs?l_rQTNcyz4d+Qg@3m+z3xl?v#a+I>wgo(3KYdOv^pOpF-eX;#=mr%x4u`T`I z<}(&6OuQtd>iKKE!0oeL_ZRg~=zVcE@%hJZs~xW!fA^1y-Syz~i3{(Wqy$rL?{9d! ze0R@Jzib!b(mz>Avz~GP%Dv&d?3d{8%r&v$Tc@u6<*jh_JKH5=2Yv5FhTPMBOJq7_ z++S#1wy0E|<#ec-$5zFXjGMm?WV83Y^cMX5`h!LAr3@3Rj=usscIZ8b-C!*gW21WL z^~qO1qe>30XTED``q1Ka!lvI6-E$sR$z z3=CCj3=9n|3=F@3LJcn%7)lKo7+xhXFj&oCU=S~uvn$XBD3OyI;hE;^%b*2hb1<+l z3NbJPS&Tr)z$nE4G7ZRLuw#^lv)$S=8Cam=en1)oJb)Oa4ni|6V1lcVSip>6gOsLN z?z#%3I14-?iy0WWg+Z8+Vb&a=ub3ufhD4M^`1)8S=jZArrsOB3>Q&?xfOIj~R9FF- zxv3?I3Kh9IdBs*0wn|_XRzNmLSYJs2tfVB{Rw=?aK*2e`C{@8s&p^*W$&O1wLBXad zCCw_x#SN+*$g@?-C@Cqh($_C9FV`zK*2^zS*Eh7ZwA42+(l;{F1**_3uFNY*tkBIX zR)!b?Gsh*hIJqdZpd>RtPXT0ZVp4u-iLH_n$Rap^xU(cP4PjGWG1OZ?59)(t^bPe4 z^s#A6t;oco4I~562KE=kIvbE-R*^xe#rZj8&$PP_iJpJkCAO4YM4(ro?GW|avskbwEr{B(rhsu8_ zzjTk-9#l7Fk9ov}9a~s0uwUd{IQ#wH{RgFGJzaNAU3d7=E|V;Z*7-NQvdap zZOaSowB?o`X89$SCx>!0a5lkfC?7X0Y)foliT_Xh$!s~P&to6HZ& zRxtd&`OK_d@;}d)gS(ziG<TK)_2*BP&lX|DLcbm5K>6I$ L)z4*}Q$iB}%9ESS literal 0 HcmV?d00001 diff --git a/apps/android/app/src/main/res/drawable-xhdpi/ntf_service_icon.png b/apps/android/app/src/main/res/drawable-xhdpi/ntf_service_icon.png new file mode 100644 index 0000000000000000000000000000000000000000..950a783161530e65694e4ad2320436f3c210e410 GIT binary patch literal 1840 zcmeAS@N?(olHy`uVBq!ia0vp^1|ZDA1|-9oezpTCmUKs7M+SzC{oH>NS%G|oWRD45dJguM!v-tY$DUh!@P+6=(yL$VrXxO!M_+&;qhK7+4sE z7?^=9Mj&Khlwtsx24peVF-pVPZta;2EKqSjAPoW@Knzj`p_vvi!BrS6U`DV(N@J}T zmjEfw0*}aI1_o|n5N2eUHAjMhfoW1^NJL45ua8x7ey(0(N`6wRUPW#JNEd@mg%yyQ zn_7~nP?4LHS8P>bs{~eI1!RMS^_3LBN=mYAl_Got6rA&mQWebf4D<|??6?#Z6l{u8 z(yW49+@RWlJX@uVl9B=|ef{$Ca=mh6z5JqdeM3u2OML?)eIp}XpbFjM%Dj@q3f;V7 zWr!g#b6ir3lZ!G7N;32F6hP)CCgqow*eWT3EP?}wJ4-Ut5H{r%L%jv`pgu@O-%!s$ zADgz+icB2ZKr#?*V1GfZvjG`q6&aLToS#z)a+aOBkqy`e6hVahAQ~dDX+Rc4*Wh22 znF-m&{c!2iNs|Mk_1$vjXo&WkYW*%M8KlJG-AhPqYqDSc3dwxR_QP>Fi-GwaSX{| zeLKy%BiK=-ZSo7YaPe42mxE3RkFri@6?6$)!y=fIBjU1QbI7($!c7X(xUy0gPHjzi z$*iNZMIf?;b-U5j{8$w`v)w1N9(_MQce2lU;aKc7=C_y5jLPrd0nniE7k zxKvmtF?lvFaR^et&HeA&ShJtke75h?Lp8?p&zt|gT7G=@kNU%J<&4Zf{PBrNk~e9F)T}#?ek`7n$8`FD z%t!MrkHkJmf7*Ta$Cg>e>Nohpn)<(1)$WSWId|x9V(F2`ZU++!A~$s?H}|RW>!2}F?HqEpQT3Z zz3a_FKCN11sC};L?ee2bFKu{!>(O?B>ZjgsU)(z)w@56Zs(0X z6u-`p%i<1qZOk04T^2^>8PCdW-ri8}$onGs-Rj}%s~47DU2b+P{EXe<>W^pFlrb}Y zOcgr~H2ULqp(3VRO(Ba~UmW94Qrdl5Mr8e`y8XN?OLtyPd>;R&fVrFJiCyV_$qOPC z@oU5O|FY_?U9_LYWZBUgPyf%il$Hjayu)uH*8fp-^W@6T{Ru}t2+hB^yQNiJqq`(- z$!Vp@7j{2)Ss=@LzVXaEuWP60eT%#P;@$U}?_AaK(|;^dKcctsV`(S<%|BU(z4!Dz zIlRu%#YE#PQ&06g-FvqlYkgSeE8)K{_CR*trE`^YH(kkL=6A?A7MvqDrJ?$N=3AFL zYIl^fw%)SntX4=n&++bacmCvD*PDy{fP}dRIbPc5G3$xP;)@mm8Y0&ohaX5Tn9aod=GBYsIz12HD-|-mVQ>v#D`)8l z+S2ZSF1L#%bNk7=EniYEx4V9StT{t*eQ@umliU3dl`8R{c(+7Jb2|fXp5@O2cANEN zo~_l(`EPQ6mX1+J+09>H@n=*`8#_I-QTX`zQX~^^Uay SoW^@V^@FFYpUXO@geCwu4ZErU literal 0 HcmV?d00001 diff --git a/apps/android/app/src/main/res/drawable-xxhdpi/ntf_service_icon.png b/apps/android/app/src/main/res/drawable-xxhdpi/ntf_service_icon.png new file mode 100644 index 0000000000000000000000000000000000000000..81da12bb9256d7144ca32305ba43692536ba5260 GIT binary patch literal 2489 zcmcImeLT}^8~@F=$V-PzlgQ3eI>JVew{2F-OB5xcv7On*yu@s6!xV*bjyO@%3#BI| z$H@@U9EMh(rnl1`@0=VCQE{l$B<7{F(Nms2oj;%Z_ql)9b$_qxdws9_ci(^fj{EG| zuA^zB2>^hOr-!Sr(t4<-#xmvG|7F#7rGbPKya@nMnXNTTgDTgE5D#B(064e-0FsXZ zfI!!W+C?jPyOl`}Ge$75qqsQCDJ>-f#q zEKWGe#>vSEg|Yhh{kSdV22rXA%ElUv`WlVFkNgLkDzZph*w>;QPE`yO=*!@;qGMHU z;T>#o3kv@Oe(rCPK>QkEDflH}Hz$&z{3HtsHXj9+VoUN>ePVnf`HX0yYb28q!&P>}AtJ7cOdCvxw#Z!BFamaH?lrX<>tgSL!7RoVuklT!0_m0i7{& z7fP6t{lPB5@M%*vY}OHr6$@J;60wesj)b*kLb9LNG1`+C5(-+Um9t8^ub);?kK-hY zM@83D#JAO{E3X!%&|x@mHTsa>jyCG`?hBHtery4zYDoJbOVZZwj_}Qd7P9xXSllKd zJb$ws3_Io&l(Uyd0X7+26phP5DO!A(F=#_Zad#c*^gUNa&29F9XJvt73dy^EH@0E! z#;k(w&aQmLV1Ggd2-dmw2DRF#9yDZGSy0w;=lXM|P4UPU=rY(b(YjM35wF$Flkd_= zNqzi0jQ)37E^ZA|nZ ztt?MV_g4JBNCvs06Nsh(sF#owSab94Y*67?@T2S7V@LtfZPzCA^7611Js_TWfL`X2 z6@%|3Wd&t%(rozMp`da6$y{!f-|Qw5p=Q!YE@;KCnAn)--0OR)VQ6!OeIN^& z)>#3I22V!#m;E``G@hiP9YpR4u(R*9Z-Lk8Nt??ngJfp5zTJq4zDr&9hv3b72y`b> z;cT!_9_AI}c_DD^L{PU5HSo#LPl?#-*}<-3>$B#5pRBg~;T*G+Ob&N`jxjQmrV}$- zDWWv>>Z_ZRrXNvWBTS%gUBit}6_%0d394#U`nTU^$5*XLRm{x9u4ox3A?eK=NcGbl zar1Ssg*&AQd%Tk~@a_TV*9eW5ux3ID$?51|t#SCp#!)9OW53Y<9b-oWg(Z9Zc<#Xv zFVyFqwH;PE5B^1lINRRj{5Wi{xz|O3_{>qqlKWSQpzu9eZu-o97LoZa=WdPp&z_p7 z?_;&<=;(CJC=`c(7Uu9BIGV*^1Q{arUI`Pl@4uO3I7SKOk&+t^OpMrkdt?(islh`} zuSS2^<2v-m{Avb0yNjaz9%eWy+xN0?YdqmhCe?1Zyyj+)Nw>a!Xy)aPr+v^mU;kB? zA!mow71;F4ZSiC>tf$G89s-xl`aH|H-%?%-t#>I6uCgrDLXfQ9hOiBZiBWrQ9-k03 zxlC+PQW%z~3wWpod^xhN}qS>Gg0Pr{{>SIA<%pl2n)$EcKR+ za6^h77TMjvmUJ06(*4+C+({i5HFZAt{&K6v1r4$h`K&OJO}7){gC z`Ji68cX)l&2lb>Ay{|1~iR~!CRgeZt+P<)1~CzyImdMyhBq?_ZM?} zEh<2zfYInJp+42v*u292oHR3|3XS B`#%5x literal 0 HcmV?d00001 diff --git a/apps/android/app/src/main/res/drawable-xxxhdpi/ntf_service_icon.png b/apps/android/app/src/main/res/drawable-xxxhdpi/ntf_service_icon.png new file mode 100644 index 0000000000000000000000000000000000000000..4ba82576b5df9e5ba50a3be56f28296c87454725 GIT binary patch literal 2812 zcmdT`iCa?J7C$0}qEb2JfL%>rmX&~*6Cp*~;Oxyb4NDObal*g?C)CnPGqar27gjHG zs_^PH8)dlV%}6sd$xKC48%(e=>1uhQy4CmYyMMsj=R0Suz1Huy*4k_D^PQ9J>%B!A zY77McK-+Dr>o$c9Ro?0g6wl#OrlUfDDR?hD05lxaoFl3!=4Pa=+q?iE$r1q4GXdZa zg(>|x0PIBpz{^koz?1@jL43v4pRo#uD>=|D!pjR-rO?#@kctkVs?byv7jTFQfIsU1 zpopXxpi0m;OK7F)cU|cuxwH={ASmkgz=S|APYj6`iy(&6!pI0#Y`hWxU|AT28cR+f znz3SI;usi~v-xKPMxiUsNOQB#kc4Pw^FS|OGZz}2Y-W!@AyDQxsF|4=mL48~+2*?W zD_t>jHjhk5h{qt2OePb-v_;V96r_!llM@n!MxxQy3WPNyF)o3~vW{a|dq|PUG8o2}$|A=Exl&`vaSTOiI467T=PZA7e6RBdV&Fd!e{lRa(S;U6qx;1Z zNo1VO*IYlCen2a$#`w^wWJN=jZBxSkX8VfAB9%S;p~qh~@UvC1gE%M_`Rz2|pvRd3 zX8`~*>*k8z&Qf`Ok`S}BNB`iIwf6+D=hY(j7V+Kb5I^~>~vmBXiBZi;p9c@U8L zoG{zYFlUV(W$xZ^xO!!64j2jskLn<(R^Y-#ka7=%Im~id^Q+`mq$m)_8WZKFvhdMv zoQRZ&&Yj8g(XVfei>4CCv$8;^H>_L)&HO(Rh5n)Y_B9*rBpNjd-+()x?0enUBWS3p zZ+)QccPRVql26`lsiHTJwLCri{0hbg;iUe1S`kL|CZ?v+C>m`&=j~`EEHBlhBQGzH z-P6^z$MOSV>Gk618rBu<2b$Tk3v)Mg9$C)ilOWIAU=;^PWJX#-R|{RdY3`u5fs275 zfoLgNqs6!BgzGyPG2u95rpM`pkCufE??@n-W(Y|n66a!I!|=n7f3Is}PKb{a za?k1HhlfbC*{c2EUYov zL1GZUaOJ@>lrq(39Rq+2O2wTJG(m`%a)gBmQ+<$y>D)AX8-=7_nigPGCuWmmxe=yos7cLzFk@G z)g@EMg5mgOtIKA1yJS9&n*I}pN0}Ru4?O}SI4x~nd!6UB-wUit52Ec|EM{kEEW>8} zif7AXiKa1Hbwf-U%yXlEqi_om@@~UGeb9ZCCjx63C|4LZq2*AP`Kxb|tZCY9Oh>MY z)f84%`-|RN$n3G|aNcO`ZMxbEsq}K#uJL*G@=E>Mlb?EdG)Y_w(0&p=5F&}F#wMRI z!_~~GO{&dse;K>l3Y!G=vS)W;GMai~T0!qdboO;DbgP~!C_{vZJX?Q&vo-Q(mmEVe;(z*B7w3RS$cHx;w)t zrk79IYIDN--02Fkp(JW>hwqhwp8Zf!E*uY z5gkDpqWa0>#~1fnIry|v?c29;?DX?T`pb5-1V8I9pJ^yhGU7xHLx;q0J5@i< zB*hMAt9$?P;}=bhx^_oDBwH2#QU5rTZc;UfVjz$&N2CHuQC>KLT&BT$wIcktsS8ThEI46^hYhu_=21h8(wwe9?C_YJeiE!LwCHA?cyTh9eUE&H?j42s_OyC zna%o_N~WFebhqzGSttmKA4A-_KDZGFh8in74$zmOpRROEnF8$)_?qD zEm!EVG{v~h=DNm;2Mb@CSmShMM0$OV7&9}v3*C$yhY8wz8*9TY(>E`02B5^{2!Hh% z-9gw%K=qzZsoYksIh)u1{nnMBrK0LTdI?rLSiA+1c67bCqZp(_nW`K~yBf4z-wyHfgjmxxCQ$ z5WhVQhD-0NpE~craDMVUGeheShTJF^5|9-plDhV()D7^{z{wIf$NyBCtcFi@j#oi= zATcO_c!NzyjT^coILqaTbAB<5Ha0Yjl)iXzrLg=mKbC8hvLk$b@d4ZJhHIUv+8uHi z*@6kUvGGgk>BbRj7zzVQXg!AOmpFSR2MA;np*GD(MhBvPg YaA&aDJI^jy`J?Ez$=mhf#?bwL0=FBZXaE2J literal 0 HcmV?d00001 diff --git a/apps/ios/SimpleX NSE/NotificationService.swift b/apps/ios/SimpleX NSE/NotificationService.swift index dcee1bf91..0f93abd8b 100644 --- a/apps/ios/SimpleX NSE/NotificationService.swift +++ b/apps/ios/SimpleX NSE/NotificationService.swift @@ -179,6 +179,7 @@ func apiGetNtfMessage(nonce: String, encNtfInfo: String) -> NtfMessages? { if case let .ntfMessages(connEntity, msgTs, ntfMessages) = r { return NtfMessages(connEntity: connEntity, msgTs: msgTs, ntfMessages: ntfMessages) } + logger.debug("apiGetNtfMessage ignored response: \(String.init(describing: r), privacy: .public)") return nil }