Support for sealed sender - Part 2
This commit is contained in:
parent
5f31762220
commit
2acab563d9
51 changed files with 819 additions and 394 deletions
127
build.gradle
127
build.gradle
|
@ -77,7 +77,7 @@ dependencies {
|
|||
compile 'com.google.android.exoplayer:exoplayer-core:2.8.4'
|
||||
compile 'com.google.android.exoplayer:exoplayer-ui:2.8.4'
|
||||
|
||||
compile 'org.whispersystems:signal-service-android:2.10.0-RC1'
|
||||
compile 'org.whispersystems:signal-service-android:2.10.0'
|
||||
compile 'org.whispersystems:webrtc-android:M69'
|
||||
|
||||
compile "me.leolin:ShortcutBadger:1.1.16"
|
||||
|
@ -147,6 +147,127 @@ dependencies {
|
|||
}
|
||||
}
|
||||
|
||||
dependencyVerification {
|
||||
verify = [
|
||||
'com.android.support:design:7874ad1904eedc74aa41cffffb7f759d8990056f3bbbc9264911651c67c42f5f',
|
||||
'com.android.support:preference-v14:8133c6e19233fa51e036a341e6d3f4adeead3375cebf777efced0fe154c3267e',
|
||||
'com.android.support:preference-v7:75eabe936d1fc3b178450a554c4d433466036f2be6d6dccdf971eac9590fdbf5',
|
||||
'com.pnikosis:materialish-progress:d71d80e00717a096784482aee21001a9d299fec3833e4ebd87739ed36cf77c54',
|
||||
'pl.tajchert:waitingdots:2835d49e0787dbcb606c5a60021ced66578503b1e9fddcd7a5ef0cd5f095ba2c',
|
||||
'mobi.upod:time-duration-picker:db469ce0f48dd96b892eac424ed76870e54bf00fe0a28cdcddfbe5f2a226a0e1',
|
||||
'com.codewaves.stickyheadergrid:stickyheadergrid:5b4aa6a52a957cfd55f60f4220c11c0c371385a3cb9786cae03c260dcdef5794',
|
||||
'com.android.support:appcompat-v7:a3a8e5230359746ed91801579b5fbe4668e3b1c4e6a14c7d67c8f58cb0311752',
|
||||
'com.melnykov:floatingactionbutton:15d58d4fac0f7a288d0e5301bbaf501a146f5b3f5921277811bf99bd3b397263',
|
||||
'com.android.support:recyclerview-v7:eb296414c1f6d4c7b522f69fe50588ea85297855db0e7806c24eb4f75409587d',
|
||||
'com.android.support:support-v13:491f940c5d6d2ec7678fa2f14bd4bbbe8bf776e2c776d04bf0e5c2175975be43',
|
||||
'com.android.support:cardview-v7:bc9e6b0e06ce1205f1db34f0e6193019613d19cfeb54cdccea722340d1c60f26',
|
||||
'com.android.support:gridlayout-v7:5029529f7db66f8773426bf7318645f0840fc50d74f66355cd60c5e58d2da087',
|
||||
'com.android.support:exifinterface:bbf44e519edd6333a24a3285aa21fd00181b920b81ca8aa89a8899f03ab4d6b0',
|
||||
'com.android.support:multidex:ecf6098572e23b5155bab3b9a82b2fd1530eda6c6c157745e0f5287c66eec60c',
|
||||
'android.arch.work:work-runtime:eda29b2cad202dee05a2e5aafe0a37c93ba9cde8f7cc0d0c8926a9f1a9498a8f',
|
||||
'android.arch.lifecycle:extensions:429426b2feec2245ffc5e75b3b5309bedb36159cf06dc71843ae43526ac289b6',
|
||||
'android.arch.lifecycle:common-java8:7078b5c8ccb94203df9cc2a463c69cf0021596e6cf966d78fbfd697aaafe0630',
|
||||
'com.google.android.gms:play-services-gcm:312e61253a236f2d9b750b9c04fc92fd190d23b0b2755c99de6ce4a28b259dae',
|
||||
'com.google.android.gms:play-services-places:abf3a4a3b146ec7e6e753be62775e512868cf37d6f88ffe2d81167b33b57132b',
|
||||
'com.google.android.gms:play-services-maps:45e8021e7ddac4a44a82a0e9698991389ded3023d35c58f38dbd86d54211ec0e',
|
||||
'com.google.android.exoplayer:exoplayer-ui:027557b2d69b15e1852a2530b36971f0dcc177abae240ee35e05f63502cdb0a7',
|
||||
'com.google.android.exoplayer:exoplayer-core:e69b409e11887c955deb373357c30eeabf183395db0092b4817e0f80bb467d5b',
|
||||
'org.whispersystems:signal-service-android:f6f144dc5df938b3a7d58dacf734f3f673e402b241a51b429de6b19ea3ef0393',
|
||||
'org.whispersystems:webrtc-android:5493c92141ce884fc5ce8240d783232f4fe14bd17a8d0d7d1bd4944d0bd1682f',
|
||||
'me.leolin:ShortcutBadger:e3cb3e7625892129b0c92dd5e4bc649faffdd526d5af26d9c45ee31ff8851774',
|
||||
'se.emilsjolander:stickylistheaders:a08ca948aa6b220f09d82f16bbbac395f6b78897e9eeac6a9f0b0ba755928eeb',
|
||||
'com.jpardogo.materialtabstrip:library:c6ef812fba4f74be7dc4a905faa4c2908cba261a94c13d4f96d5e67e4aad4aaa',
|
||||
'org.apache.httpcomponents:httpclient-android:6f56466a9bd0d42934b90bfbfe9977a8b654c058bf44a12bdc2877c4e1f033f1',
|
||||
'com.github.chrisbanes:PhotoView:ed06775308da260e1fd86d1d3288988fcd3d80db24ce0d7c9fcfedc39e622292',
|
||||
'com.github.bumptech.glide:glide:997de7ac95be6c944d3b8cbe13de11307736ea45451c1b09a6cec7c328ead59f',
|
||||
'com.makeramen:roundedimageview:1f5a1865796b308c6cdd114acc6e78408b110f0a62fc63553278fbeacd489cd1',
|
||||
'org.greenrobot:eventbus:180d4212467df06f2fbc9c8d8a2984533ac79c87769ad883bc421612f0b4e17c',
|
||||
'com.soundcloud.android:android-crop:ffd4b973cf6e97f7d64118a0dc088df50e9066fd5634fe6911dd0c0c5d346177',
|
||||
'com.google.zxing:android-integration:89e56aadf1164bd71e57949163c53abf90af368b51669c0d4a47a163335f95c4',
|
||||
'com.squareup.dagger:dagger:789aca24537022e49f91fc6444078d9de8f1dd99e1bfb090f18491b186967883',
|
||||
'com.amulyakhare:com.amulyakhare.textdrawable:54c92b5fba38cfd316a07e5a30528068f45ce8515a6890f1297df4c401af5dcb',
|
||||
'com.google.zxing:core:b4d82452e7a6bf6ec2698904b332431717ed8f9a850224f295aec89de80f2259',
|
||||
'com.davemorrissey.labs:subsampling-scale-image-view:550c5baa07e0bb4ff0a18b705e96d34436d22619248bd8c08c08c730b1f55cfe',
|
||||
'cn.carbswang.android:NumberPickerView:18b3c316d62c7c277978a8d4ed57a5b8f4e943762264960f579a8a549c756729',
|
||||
'com.tomergoldst.android:tooltips:4c56697dd1ad64b8066535c61f961a6d901e7ae5d97ae27084ba40ad620349b6',
|
||||
'com.klinkerapps:android-smsmms:e7c3328a0f3a8dd44daa8129de4e99996f3057a4546e47891b036b81e0ebf1d1',
|
||||
'com.annimon:stream:5da6e2e3e0551d61a3ea7014f04312276549e3dd739cf637996e4cf43c5535b9',
|
||||
'com.takisoft.fix:colorpicker:f5d0dbabe406a1800498ca9c1faf34db36e021d8488bf10360f29961fe3ab0d1',
|
||||
'com.github.dmytrodanylyk.circular-progress-button:library:8dc6a29a5a8db7b2ad5a9a7fda1dc9ae0893f4c8f0545732b2c63854ea693e8e',
|
||||
'org.signal:android-database-sqlcipher:33d4063336893af00b9d68b418e7b290cace74c20ce8aacffddc0911010d3d73',
|
||||
'com.googlecode.ez-vcard:ez-vcard:7e24ad50b222d2f70ac91bdccfa3c0f6200b078d797cb784837f75e77bb4210f',
|
||||
'com.google.android.gms:play-services-iid:54e919f9957b8b7820da7ee9b83471d00d0cac1cf08ddea8b5b41aea80bb1a70',
|
||||
'com.google.android.gms:play-services-base:0ca636a8fc9a5af45e607cdcd61783bf5d561cbbb0f862021ce69606eee5ad49',
|
||||
'com.google.android.gms:play-services-tasks:69ec265168e601d0203d04cd42e34bb019b2f029aa1e16fabd38a5153eea2086',
|
||||
'com.google.android.gms:play-services-basement:95dd882c5ffba15b9a99de3fefb05d3a01946623af67454ca00055d222f85a8d',
|
||||
'com.android.support:support-v4:8b9031381c678d628c9e47b566ae1d161e1c9710f7855c759beeac7596cecf30',
|
||||
'com.android.support:support-fragment:3772fc738ada86824ba1a4b3f197c3dbd67b7ddcfe2c9db1de95ef2e3487a915',
|
||||
'com.android.support:animated-vector-drawable:271ecbc906cda8dcd9e655ba0473129c3408a4189c806f616c378e6fd18fb3b7',
|
||||
'com.android.support:support-core-ui:bbc7f65fc95649464733af373361532ab5f9f3b749c3badaa2bbf27e574b6c6f',
|
||||
'com.android.support:transition:45d09fc51284c17bbab300f5122512ac7d7348a6d23bda2051648bbe76cc9aa5',
|
||||
'com.android.support:viewpager:013c4c53058758ec104dbae970be58159f75dfe342ba8b937d15ff5282e35ffc',
|
||||
'com.android.support:coordinatorlayout:9dfacd80423dc979048fbaed83c0ee543c46259feb2417377e79a656888d3892',
|
||||
'com.android.support:drawerlayout:8f6809afae4793550c37461c9810e954ae6a23dbb4d23e5333bf18148df1150a',
|
||||
'com.android.support:slidingpanelayout:d1d234f66a1b36a9aee9b94fa6c66f97128c0828078c8e889e9037ec898cd600',
|
||||
'com.android.support:customview:98db03845f994e08248bf701c1ff0ccaa12e70f94251ec9272900f0f694e072b',
|
||||
'com.android.support:swiperefreshlayout:a3b41f7f6730866b49865e86e49f988d4858699765f534300fb2ff5f9325e712',
|
||||
'com.android.support:asynclayoutinflater:115bde87721f7334579b0c735f60dd7c98af1bb7f34010c5b0553b95dc351aa2',
|
||||
'android.arch.persistence.room:runtime:c21810eaafce370f1c9df1365393f55f962370a0d8b0b38b4771052c7021b737',
|
||||
'com.android.support:support-core-utils:c81e1e98ca3cb2edae002c69cf35b22aec364b8cb2f1042c97e206eb5790ac41',
|
||||
'com.android.support:loader:920b85efd72dc33e915b0f88a883fe73b88483c6df8751a741e17611f2460341',
|
||||
'com.android.support:support-vector-drawable:f658986d968172bccfed28578471c96050780fe5e133861e4d331069cc373f4d',
|
||||
'com.android.support:support-media-compat:266eff9605f515013eee1ebdbd8818a9270696dc807f34bbcc5fc11fb61a22c7',
|
||||
'com.android.support:support-compat:e17e3b01dbea3f9ea1c86943292f903ca93d2231c6242e456e0b6a9c5817118a',
|
||||
'com.android.support:versionedparcelable:60eb1cb08f71b65c3f6123135e03ebeb5930b5e126e1e5b2ac91b386908c9d02',
|
||||
'com.android.support:collections:93c258c8a09f531a267653829742c0f8f6da0e348b11cb8655b0855628f2d4f0',
|
||||
'android.arch.lifecycle:livedata:50ab0490c1ff1a7cfb4e554032998b080888946d0dd424f39900efc4a1bcd750',
|
||||
'android.arch.lifecycle:livedata-core:d6fdd8b985d6178d7ea2f16986a24e83f1bee936b74d43167c69e08d3cc12c50',
|
||||
'android.arch.lifecycle:runtime:c4e4be66c1b2f0abec593571454e1de14013f7e0f96bf2a9f212931a48cae550',
|
||||
'android.arch.lifecycle:common:8d378e88ebd5189e09eef623414812c868fd90aa519d6160e2311fb8b81cff56',
|
||||
'com.github.bumptech.glide:gifdecoder:59ccf3bb0cec11dab4b857382cbe0b171111b6fc62bf141adce4e1180889af15',
|
||||
'com.android.support:interpolator:7bc7ee86a0db39a4b51956f3e89842d2bd962118d57d779eb6ed6b34ba0677ea',
|
||||
'com.android.support:cursoradapter:87feffe742b8d62ca8a9833abe564838bf6a672e31c7ad1306ec4006adf90d21',
|
||||
'android.arch.persistence.room:common:7cf36bcd5f59ddc4876f887e36511bfd7b111f1eb717c0e9b6e2bcc710305ae6',
|
||||
'android.arch.persistence:db-framework:bd665448330acb90a6f551a87b0ba69169da2b8ec168b92f387997339cc14311',
|
||||
'android.arch.persistence:db:504e8c4307bfd53084924776ba3d49fed11b6f76d82dd80d5121c2d907fdfef6',
|
||||
'android.arch.core:runtime:c3215aa5873311b3f88a6f4e4a3c25ad89971bc127de8c3e1291c57f93a05c39',
|
||||
'android.arch.core:common:3a616a32f433e9e23f556b38575c31b013613d3ae85206263b7625fe1f4c151a',
|
||||
'android.arch.lifecycle:viewmodel:7de29cfaba77d6b5d5be234c57f6812d0150d087e63941af22ba1d1f8e2bc96a',
|
||||
'com.android.support:documentfile:47cdcd3e9302b7b064923f05487a5c03babbd9bbda4726b71e97791fab5d4779',
|
||||
'com.android.support:localbroadcastmanager:d287c823af5fdde72c099fcfc5f630efe9687af7a914343ae6fd92de32c8a806',
|
||||
'com.android.support:print:4be8a812d73e4a80e35b91ceae127def3f0bb9726bf3bc439aa0cc81503f5728',
|
||||
'com.android.support:support-annotations:5d5b9414f02d3fa0ee7526b8d5ddae0da67c8ecc8c4d63ffa6cf91488a93b927',
|
||||
'androidx.concurrent:futures:1f63078c41efd29d20ee3444fba93c6cdfaeeb862c6d3b6166ff8debd37d471a',
|
||||
'org.signal:signal-metadata-android:d9d798aab7ee7200373ecff8718baf8aaeb632c123604e8a41b7b4c0c97eeee1',
|
||||
'org.whispersystems:signal-service-java:092b0c23d914a5c6c04188fd06097e3351ad251d631e95cd0119ac60c85969d8',
|
||||
'com.github.bumptech.glide:disklrucache:c1b1b6f5bbd01e2fcdc9d7f60913c8d338bdb65ed4a93bfa02b56f19daaade4b',
|
||||
'com.github.bumptech.glide:annotations:bede99ef9f71517a4274bac18fd3e483e9f2b6108d7d6fe8f4949be4aa4d9512',
|
||||
'com.nineoldandroids:library:68025a14e3e7673d6ad2f95e4b46d78d7d068343aa99256b686fe59de1b3163a',
|
||||
'javax.inject:javax.inject:91c77044a50c481636c32d916fd89c9118a72195390452c81065080f957de7ff',
|
||||
'com.klinkerapps:logger:177e325259a8b111ad6745ec10db5861723c99f402222b80629f576f49408541',
|
||||
'com.google.android:flexbox:a9989fd13ae2ee42765dfc515fe362edf4f326e74925d02a10369df8092a4935',
|
||||
'org.jsoup:jsoup:abeaf34795a4de70f72aed6de5966d2955ec7eb348eeb813324f23c999575473',
|
||||
'com.google.guava:listenablefuture:e4ad7607e5c0477c6f890ef26a49cb8d1bb4dffb650bab4502afee64644e3069',
|
||||
'androidx.annotation:annotation:04f22f257944ce223701d5aa1bdc36fb7f4594e87b539044045cd161d965468e',
|
||||
'org.whispersystems:signal-protocol-android:b41b7c3a47b0a4ce35802474ae7c5ddc8f033d80209e98abf7ec669543b2b3ee',
|
||||
'org.signal:signal-metadata-java:af1d0dd766b1e301ed1c44e65161084cf03e2587fe97fdd29ecbea58c6aa6930',
|
||||
'org.whispersystems:signal-protocol-java:b08207f7e1847228f2a1f0d49e113f93c96c6ed8490be14edddd4be55b2a4a4e',
|
||||
'com.google.protobuf:protobuf-java:e0c1c64575c005601725e7c6a02cebf9e1285e888f756b2a1d73ffa8d725cc74',
|
||||
'com.googlecode.libphonenumber:libphonenumber:183392c0565be16d3f6f86680b4106bbde6fe31a402ad21bf9823d938c0c8706',
|
||||
'com.fasterxml.jackson.core:jackson-databind:0fb4e079c118e752cc94c15ad22e6782b0dfc5dc09145f4813fb39d82e686047',
|
||||
'com.squareup.okhttp3:okhttp:7265adbd6f028aade307f58569d814835cd02bc9beffb70c25f72c9de50d61c4',
|
||||
'com.madgag.spongycastle:pkix:0d9cca6991f68eb373cfad309d5268c9fc38db5efb5fe00dcccf5c973af1eca1',
|
||||
'com.madgag.spongycastle:prov:b8c3fec3a59aac1aa04ccf4dad7179351e54ef7672f53f508151b614c131398a',
|
||||
'org.threeten:threetenbp:f4c23ffaaed717c3b99c003e0ee02d6d66377fd47d866fec7d971bd8644fc1a7',
|
||||
'org.whispersystems:curve25519-android:82595394422b957d4a5b5f1b27b75ba25cf6dc4db4d312418ca38cd6fff279ca',
|
||||
'com.fasterxml.jackson.core:jackson-annotations:45d32ac61ef8a744b464c54c2b3414be571016dd46bfc2bec226761cf7ae457a',
|
||||
'com.fasterxml.jackson.core:jackson-core:a2bebaa325ad25455b02149c67e6052367a7d7fc1ce77de000eed284a5214eac',
|
||||
'com.squareup.okio:okio:734269c3ebc5090e3b23566db558f421f0b4027277c79ad5d176b8ec168bb850',
|
||||
'com.madgag.spongycastle:core:8d6240b974b0aca4d3da9c7dd44d42339d8a374358aca5fc98e50a995764511f',
|
||||
'org.whispersystems:curve25519-java:7dd659d8822c06c3aea1a47f18fac9e5761e29cab8100030b877db445005f03e',
|
||||
]
|
||||
}
|
||||
|
||||
android {
|
||||
flavorDimensions "none"
|
||||
compileSdkVersion 28
|
||||
|
@ -169,7 +290,7 @@ android {
|
|||
project.ext.set("archivesBaseName", "Signal");
|
||||
|
||||
buildConfigField "long", "BUILD_TIMESTAMP", getLastCommitTimestamp() + "L"
|
||||
buildConfigField "String", "SIGNAL_URL", "\"https://textsecure-service-staging.whispersystems.org\""
|
||||
buildConfigField "String", "SIGNAL_URL", "\"https://textsecure-service.whispersystems.org\""
|
||||
buildConfigField "String", "SIGNAL_CDN_URL", "\"https://cdn.signal.org\""
|
||||
buildConfigField "String", "SIGNAL_CONTACT_DISCOVERY_URL", "\"https://api.directory.signal.org\""
|
||||
buildConfigField "String", "SIGNAL_SERVICE_STATUS_URL", "\"uptime.signal.org\""
|
||||
|
@ -178,7 +299,7 @@ android {
|
|||
buildConfigField "String", "USER_AGENT", "\"OWA\""
|
||||
buildConfigField "boolean", "DEV_BUILD", "false"
|
||||
buildConfigField "String", "MRENCLAVE", "\"cd6cfc342937b23b1bdd3bbf9721aa5615ac9ff50a75c5527d441cd3276826c9\""
|
||||
buildConfigField "String", "UNIDENTIFIED_SENDER_TRUST_ROOT", "\"BbqY1DzohE4NUZoVF+L18oUPrK3kILllLEJh2UnPSsEx\""
|
||||
buildConfigField "String", "UNIDENTIFIED_SENDER_TRUST_ROOT", "\"BXu6QIKVz5MA8gstzfOgRQGqyLqOwNKHL6INkv3IHWMF\""
|
||||
|
||||
ndk {
|
||||
abiFilters "armeabi", "armeabi-v7a", "x86"
|
||||
|
|
BIN
res/drawable-hdpi/ic_unidentified_delivery.png
Normal file
BIN
res/drawable-hdpi/ic_unidentified_delivery.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 478 B |
BIN
res/drawable-mdpi/ic_unidentified_delivery.png
Normal file
BIN
res/drawable-mdpi/ic_unidentified_delivery.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 311 B |
BIN
res/drawable-xhdpi/ic_unidentified_delivery.png
Normal file
BIN
res/drawable-xhdpi/ic_unidentified_delivery.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 490 B |
BIN
res/drawable-xxhdpi/ic_unidentified_delivery.png
Normal file
BIN
res/drawable-xxhdpi/ic_unidentified_delivery.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 765 B |
BIN
res/drawable-xxxhdpi/ic_unidentified_delivery.png
Normal file
BIN
res/drawable-xxxhdpi/ic_unidentified_delivery.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 988 B |
|
@ -20,17 +20,39 @@
|
|||
android:paddingLeft="10dp"
|
||||
android:paddingRight="10dp">
|
||||
|
||||
<TextView android:id="@+id/error_text"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:visibility="gone"
|
||||
android:textSize="16sp"
|
||||
android:padding="5dp"
|
||||
tools:visibility="visible"
|
||||
android:text="@string/message_details_header__issues_need_your_attention"
|
||||
android:drawableLeft="@drawable/ic_info_outline_light"
|
||||
android:drawableStart="@drawable/ic_info_outline_light"
|
||||
android:gravity="center_vertical" />
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content">
|
||||
|
||||
<TextView android:id="@+id/error_text"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_weight="1"
|
||||
android:visibility="gone"
|
||||
android:textSize="16sp"
|
||||
android:padding="5dp"
|
||||
tools:visibility="visible"
|
||||
android:text="@string/message_details_header__issues_need_your_attention"
|
||||
android:drawableLeft="@drawable/ic_info_outline_light"
|
||||
android:drawableStart="@drawable/ic_info_outline_light"
|
||||
android:gravity="center_vertical" />
|
||||
|
||||
<Button
|
||||
android:id="@+id/resend_button"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="38sp"
|
||||
style="@style/InfoButton"
|
||||
android:paddingLeft="10dp"
|
||||
android:paddingRight="10dp"
|
||||
android:paddingTop="5dp"
|
||||
android:paddingBottom="5dp"
|
||||
android:layout_gravity="center_vertical"
|
||||
android:drawableLeft="@drawable/ic_refresh_white_18dp"
|
||||
android:text="@string/message_recipients_list_item__resend"
|
||||
android:visibility="gone"
|
||||
tools:visibility="visible" />
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
<TableLayout android:id="@+id/metadata_container"
|
||||
android:layout_width="match_parent"
|
||||
|
|
|
@ -80,19 +80,13 @@
|
|||
android:visibility="gone"
|
||||
tools:visibility="gone" />
|
||||
|
||||
<Button android:id="@+id/resend_button"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="38sp"
|
||||
style="@style/InfoButton"
|
||||
android:paddingLeft="10dp"
|
||||
android:paddingRight="5dp"
|
||||
android:paddingTop="5dp"
|
||||
android:paddingBottom="5dp"
|
||||
android:layout_gravity="center_vertical"
|
||||
android:drawableLeft="@drawable/ic_refresh_white_18dp"
|
||||
android:text="@string/message_recipients_list_item__resend"
|
||||
android:visibility="gone"
|
||||
tools:visibility="gone" />
|
||||
<ImageView android:id="@+id/ud_indicator"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginLeft="4dp"
|
||||
android:layout_marginRight="4dp"
|
||||
android:src="@drawable/ic_unidentified_delivery"
|
||||
android:tint="?attr/conversation_item_sent_text_secondary_color"/>
|
||||
|
||||
<org.thoughtcrime.securesms.components.DeliveryStatusView
|
||||
android:id="@+id/delivery_status"
|
||||
|
|
25
res/layout/unidentified_delivery_learn_more.xml
Normal file
25
res/layout/unidentified_delivery_learn_more.xml
Normal file
|
@ -0,0 +1,25 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<LinearLayout
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:orientation="horizontal"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:gravity="center_vertical"
|
||||
android:padding="16dp">
|
||||
|
||||
<ImageView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginRight="16dp"
|
||||
android:layout_marginEnd="16dp"
|
||||
android:src="@drawable/ic_unidentified_delivery"
|
||||
android:tint="?conversation_item_sent_text_secondary_color"/>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/ud_learn_more"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/preferences_communication__sealed_sender_learn_more"
|
||||
android:textColor="@color/signal_primary"/>
|
||||
|
||||
</LinearLayout>
|
|
@ -86,6 +86,9 @@
|
|||
<string name="ClearProfileActivity_remove">Remove</string>
|
||||
<string name="ClearProfileActivity_remove_profile_photo">Remove profile photo?</string>
|
||||
|
||||
<!-- CommunicationActions -->
|
||||
<string name="CommunicationActions_no_browser_found">No web browser found.</string>
|
||||
|
||||
<!-- ConfirmIdentityDialog -->
|
||||
<string name="ConfirmIdentityDialog_your_safety_number_with_s_has_changed">Your safety number with %1$s has changed. This could either mean that someone is trying to intercept your communication, or that %2$s simply reinstalled Signal.</string>
|
||||
<string name="ConfirmIdentityDialog_you_may_wish_to_verify_your_safety_number_with_this_contact">You may wish to verify your safety number with this contact.</string>
|
||||
|
@ -1204,6 +1207,12 @@
|
|||
<string name="preferences_chats__message_text_size">Message font size</string>
|
||||
<string name="preferences_events__contact_joined_signal">Contact joined Signal</string>
|
||||
<string name="preferences_notifications__priority">Priority</string>
|
||||
<string name="preferences_communication__category_sealed_sender">Sealed Sender</string>
|
||||
<string name="preferences_communication__sealed_sender_display_indicators">Display indicators</string>
|
||||
<string name="preferences_communication__sealed_sender_display_indicators_description">Show a status icon when you select "Message details" on messages that were delivered using sealed sender.</string>
|
||||
<string name="preferences_communication__sealed_sender_allow_from_anyone">Allow from anyone</string>
|
||||
<string name="preferences_communication__sealed_sender_allow_from_anyone_description">Enable sealed sender for incoming messages from non-contacts and people with whom you have not shared your profile.</string>
|
||||
<string name="preferences_communication__sealed_sender_learn_more">Learn more</string>
|
||||
|
||||
<!-- **************************************** -->
|
||||
<!-- menus -->
|
||||
|
|
|
@ -69,6 +69,27 @@
|
|||
|
||||
<PreferenceCategory android:layout="@layout/preference_divider"/>
|
||||
|
||||
<PreferenceCategory android:title="@string/preferences_communication__category_sealed_sender">
|
||||
<org.thoughtcrime.securesms.components.SwitchPreferenceCompat
|
||||
android:defaultValue="false"
|
||||
android:key="pref_show_unidentifed_delivery_indicators"
|
||||
android:title="@string/preferences_communication__sealed_sender_display_indicators"
|
||||
android:summary="@string/preferences_communication__sealed_sender_display_indicators_description"/>
|
||||
|
||||
<org.thoughtcrime.securesms.components.SwitchPreferenceCompat
|
||||
android:defaultValue="false"
|
||||
android:key="pref_universal_unidentified_access"
|
||||
android:title="@string/preferences_communication__sealed_sender_allow_from_anyone"
|
||||
android:summary="@string/preferences_communication__sealed_sender_allow_from_anyone_description"/>
|
||||
|
||||
<Preference
|
||||
android:key="pref_unidentified_learn_more"
|
||||
android:layout="@layout/unidentified_delivery_learn_more" />
|
||||
|
||||
</PreferenceCategory>
|
||||
|
||||
<PreferenceCategory android:layout="@layout/preference_divider"/>
|
||||
|
||||
<PreferenceCategory android:title="@string/preferences_app_protection__registration_lock">
|
||||
<org.thoughtcrime.securesms.components.SwitchPreferenceCompat
|
||||
android:defaultValue="false"
|
||||
|
|
|
@ -38,6 +38,7 @@ import org.thoughtcrime.securesms.jobs.CreateSignedPreKeyJob;
|
|||
import org.thoughtcrime.securesms.jobs.GcmRefreshJob;
|
||||
import org.thoughtcrime.securesms.jobs.MultiDeviceContactUpdateJob;
|
||||
import org.thoughtcrime.securesms.jobs.PushNotificationReceiveJob;
|
||||
import org.thoughtcrime.securesms.jobs.RefreshUnidentifiedDeliveryAbilityJob;
|
||||
import org.thoughtcrime.securesms.logging.AndroidLogger;
|
||||
import org.thoughtcrime.securesms.logging.CustomSignalProtocolLogger;
|
||||
import org.thoughtcrime.securesms.logging.Log;
|
||||
|
@ -109,6 +110,7 @@ public class ApplicationContext extends MultiDexApplication implements Dependenc
|
|||
initializeCircumvention();
|
||||
initializeWebRtc();
|
||||
initializePendingMessages();
|
||||
initializeUnidentifiedDeliveryAbilityRefresh();
|
||||
NotificationChannels.create(this);
|
||||
ProcessLifecycleOwner.get().getLifecycle().addObserver(this);
|
||||
}
|
||||
|
@ -281,4 +283,10 @@ public class ApplicationContext extends MultiDexApplication implements Dependenc
|
|||
TextSecurePreferences.setNeedsMessagePull(this, false);
|
||||
}
|
||||
}
|
||||
|
||||
private void initializeUnidentifiedDeliveryAbilityRefresh() {
|
||||
if (TextSecurePreferences.isMultiDevice(this) && !TextSecurePreferences.isUnidentifiedDeliveryEnabled(this)) {
|
||||
jobManager.add(new RefreshUnidentifiedDeliveryAbilityJob(this));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -52,7 +52,6 @@ import org.thoughtcrime.securesms.jobs.PushDecryptJob;
|
|||
import org.thoughtcrime.securesms.jobs.RefreshAttributesJob;
|
||||
import org.thoughtcrime.securesms.mms.GlideApp;
|
||||
import org.thoughtcrime.securesms.notifications.MessageNotifier;
|
||||
import org.thoughtcrime.securesms.recipients.Recipient;
|
||||
import org.thoughtcrime.securesms.service.KeyCachingService;
|
||||
import org.thoughtcrime.securesms.util.FileUtils;
|
||||
import org.thoughtcrime.securesms.util.TextSecurePreferences;
|
||||
|
@ -95,6 +94,7 @@ public class DatabaseUpgradeActivity extends BaseActivity {
|
|||
public static final int IMAGE_CACHE_CLEANUP = 406;
|
||||
public static final int WORKMANAGER_MIGRATION = 408;
|
||||
public static final int COLOR_MIGRATION = 412;
|
||||
public static final int UNIDENTIFIED_DELIVERY = 422;
|
||||
|
||||
private static final SortedSet<Integer> UPGRADE_VERSIONS = new TreeSet<Integer>() {{
|
||||
add(NO_MORE_KEY_EXCHANGE_PREFIX_VERSION);
|
||||
|
@ -120,6 +120,7 @@ public class DatabaseUpgradeActivity extends BaseActivity {
|
|||
add(IMAGE_CACHE_CLEANUP);
|
||||
add(WORKMANAGER_MIGRATION);
|
||||
add(COLOR_MIGRATION);
|
||||
add(UNIDENTIFIED_DELIVERY);
|
||||
}};
|
||||
|
||||
private MasterSecret masterSecret;
|
||||
|
@ -358,6 +359,18 @@ public class DatabaseUpgradeActivity extends BaseActivity {
|
|||
Log.i(TAG, "Color migration took " + (System.currentTimeMillis() - startTime) + " ms");
|
||||
}
|
||||
|
||||
if (params[0] < UNIDENTIFIED_DELIVERY) {
|
||||
if (TextSecurePreferences.isMultiDevice(context)) {
|
||||
Log.i(TAG, "MultiDevice: Disabling UD (will be re-enabled if possible after pending refresh).");
|
||||
TextSecurePreferences.setIsUnidentifiedDeliveryEnabled(context, false);
|
||||
}
|
||||
|
||||
Log.i(TAG, "Scheduling UD attributes refresh.");
|
||||
ApplicationContext.getInstance(context)
|
||||
.getJobManager()
|
||||
.add(new RefreshAttributesJob(context));
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
|
|
|
@ -11,6 +11,7 @@ import android.os.Vibrator;
|
|||
import android.support.annotation.NonNull;
|
||||
import android.text.TextUtils;
|
||||
import android.transition.TransitionInflater;
|
||||
|
||||
import org.thoughtcrime.securesms.logging.Log;
|
||||
import android.view.MenuItem;
|
||||
import android.view.View;
|
||||
|
@ -179,6 +180,7 @@ public class DeviceActivity extends PassphraseRequiredActionBarActivity
|
|||
Optional<byte[]> profileKey = Optional.of(ProfileKeyUtil.getProfileKey(getContext()));
|
||||
|
||||
TextSecurePreferences.setMultiDevice(DeviceActivity.this, true);
|
||||
TextSecurePreferences.setIsUnidentifiedDeliveryEnabled(context, false);
|
||||
accountManager.addDevice(ephemeralId, publicKey, identityKeyPair, profileKey, verificationCode);
|
||||
|
||||
return SUCCESS;
|
||||
|
|
|
@ -9,6 +9,8 @@ import android.support.v4.app.ListFragment;
|
|||
import android.support.v4.app.LoaderManager;
|
||||
import android.support.v4.content.Loader;
|
||||
import android.support.v7.app.AlertDialog;
|
||||
|
||||
import org.thoughtcrime.securesms.jobs.RefreshUnidentifiedDeliveryAbilityJob;
|
||||
import org.thoughtcrime.securesms.logging.Log;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
|
@ -172,6 +174,10 @@ public class DeviceListFragment extends ListFragment
|
|||
protected Void doInBackground(Void... params) {
|
||||
try {
|
||||
accountManager.removeDevice(deviceId);
|
||||
|
||||
ApplicationContext.getInstance(getContext())
|
||||
.getJobManager()
|
||||
.add(new RefreshUnidentifiedDeliveryAbilityJob(getContext()));
|
||||
} catch (IOException e) {
|
||||
Log.w(TAG, e);
|
||||
Toast.makeText(getActivity(), R.string.DeviceListActivity_network_failed, Toast.LENGTH_LONG).show();
|
||||
|
|
|
@ -52,6 +52,7 @@ import org.thoughtcrime.securesms.mms.GlideRequests;
|
|||
import org.thoughtcrime.securesms.notifications.MessageNotifier;
|
||||
import org.thoughtcrime.securesms.recipients.Recipient;
|
||||
import org.thoughtcrime.securesms.recipients.RecipientModifiedListener;
|
||||
import org.thoughtcrime.securesms.sms.MessageSender;
|
||||
import org.thoughtcrime.securesms.util.DateUtils;
|
||||
import org.thoughtcrime.securesms.util.DynamicLanguage;
|
||||
import org.thoughtcrime.securesms.util.DynamicTheme;
|
||||
|
@ -87,6 +88,7 @@ public class MessageDetailsActivity extends PassphraseRequiredActionBarActivity
|
|||
private View metadataContainer;
|
||||
private View expiresContainer;
|
||||
private TextView errorText;
|
||||
private View resendButton;
|
||||
private TextView sentDate;
|
||||
private TextView receivedDate;
|
||||
private TextView expiresInText;
|
||||
|
@ -176,6 +178,7 @@ public class MessageDetailsActivity extends PassphraseRequiredActionBarActivity
|
|||
recipientsList = findViewById(R.id.recipients_list);
|
||||
metadataContainer = header.findViewById(R.id.metadata_container);
|
||||
errorText = header.findViewById(R.id.error_text);
|
||||
resendButton = header.findViewById(R.id.resend_button);
|
||||
sentDate = header.findViewById(R.id.sent_time);
|
||||
receivedContainer = header.findViewById(R.id.received_container);
|
||||
receivedDate = header.findViewById(R.id.received_time);
|
||||
|
@ -362,7 +365,7 @@ public class MessageDetailsActivity extends PassphraseRequiredActionBarActivity
|
|||
List<RecipientDeliveryStatus> recipients = new LinkedList<>();
|
||||
|
||||
if (!messageRecord.getRecipient().isGroupRecipient()) {
|
||||
recipients.add(new RecipientDeliveryStatus(messageRecord.getRecipient(), getStatusFor(messageRecord.getDeliveryReceiptCount(), messageRecord.getReadReceiptCount(), messageRecord.isPending()), -1));
|
||||
recipients.add(new RecipientDeliveryStatus(messageRecord.getRecipient(), getStatusFor(messageRecord.getDeliveryReceiptCount(), messageRecord.getReadReceiptCount(), messageRecord.isPending()), messageRecord.isUnidentified(), -1));
|
||||
} else {
|
||||
List<GroupReceiptInfo> receiptInfoList = DatabaseFactory.getGroupReceiptDatabase(context).getGroupReceiptInfo(messageRecord.getId());
|
||||
|
||||
|
@ -370,12 +373,13 @@ public class MessageDetailsActivity extends PassphraseRequiredActionBarActivity
|
|||
List<Recipient> group = DatabaseFactory.getGroupDatabase(context).getGroupMembers(messageRecord.getRecipient().getAddress().toGroupString(), false);
|
||||
|
||||
for (Recipient recipient : group) {
|
||||
recipients.add(new RecipientDeliveryStatus(recipient, RecipientDeliveryStatus.Status.UNKNOWN, -1));
|
||||
recipients.add(new RecipientDeliveryStatus(recipient, RecipientDeliveryStatus.Status.UNKNOWN, false, -1));
|
||||
}
|
||||
} else {
|
||||
for (GroupReceiptInfo info : receiptInfoList) {
|
||||
recipients.add(new RecipientDeliveryStatus(Recipient.from(context, info.getAddress(), true),
|
||||
getStatusFor(info.getStatus(), messageRecord.isPending()),
|
||||
getStatusFor(info.getStatus(), messageRecord.isPending(), messageRecord.isFailed()),
|
||||
info.isUnidentified(),
|
||||
info.getTimestamp()));
|
||||
}
|
||||
}
|
||||
|
@ -392,16 +396,28 @@ public class MessageDetailsActivity extends PassphraseRequiredActionBarActivity
|
|||
}
|
||||
|
||||
inflateMessageViewIfAbsent(messageRecord);
|
||||
|
||||
updateRecipients(messageRecord, messageRecord.getRecipient(), recipients);
|
||||
if (messageRecord.isFailed()) {
|
||||
|
||||
boolean isGroupNetworkFailure = messageRecord.isFailed() && !messageRecord.getNetworkFailures().isEmpty();
|
||||
boolean isIndividualNetworkFailure = messageRecord.isFailed() && !isPushGroup && messageRecord.getIdentityKeyMismatches().isEmpty();
|
||||
|
||||
if (isGroupNetworkFailure || isIndividualNetworkFailure) {
|
||||
errorText.setVisibility(View.VISIBLE);
|
||||
resendButton.setVisibility(View.VISIBLE);
|
||||
resendButton.setOnClickListener(this::onResendClicked);
|
||||
metadataContainer.setVisibility(View.GONE);
|
||||
} else if (messageRecord.isFailed()) {
|
||||
errorText.setVisibility(View.VISIBLE);
|
||||
resendButton.setVisibility(View.GONE);
|
||||
resendButton.setOnClickListener(null);
|
||||
metadataContainer.setVisibility(View.GONE);
|
||||
} else {
|
||||
updateTransport(messageRecord);
|
||||
updateTime(messageRecord);
|
||||
updateExpirationTime(messageRecord);
|
||||
errorText.setVisibility(View.GONE);
|
||||
resendButton.setVisibility(View.GONE);
|
||||
resendButton.setOnClickListener(null);
|
||||
metadataContainer.setVisibility(View.VISIBLE);
|
||||
}
|
||||
}
|
||||
|
@ -413,14 +429,19 @@ public class MessageDetailsActivity extends PassphraseRequiredActionBarActivity
|
|||
else return RecipientDeliveryStatus.Status.PENDING;
|
||||
}
|
||||
|
||||
private RecipientDeliveryStatus.Status getStatusFor(int groupStatus, boolean pending) {
|
||||
private RecipientDeliveryStatus.Status getStatusFor(int groupStatus, boolean pending, boolean failed) {
|
||||
if (groupStatus == GroupReceiptDatabase.STATUS_READ) return RecipientDeliveryStatus.Status.READ;
|
||||
else if (groupStatus == GroupReceiptDatabase.STATUS_DELIVERED) return RecipientDeliveryStatus.Status.DELIVERED;
|
||||
else if (groupStatus == GroupReceiptDatabase.STATUS_UNDELIVERED && failed) return RecipientDeliveryStatus.Status.UNKNOWN;
|
||||
else if (groupStatus == GroupReceiptDatabase.STATUS_UNDELIVERED && !pending) return RecipientDeliveryStatus.Status.SENT;
|
||||
else if (groupStatus == GroupReceiptDatabase.STATUS_UNDELIVERED) return RecipientDeliveryStatus.Status.PENDING;
|
||||
else if (groupStatus == GroupReceiptDatabase.STATUS_UNKNOWN) return RecipientDeliveryStatus.Status.UNKNOWN;
|
||||
throw new AssertionError();
|
||||
}
|
||||
|
||||
private void onResendClicked(View v) {
|
||||
MessageSender.resend(MessageDetailsActivity.this, messageRecord);
|
||||
resendButton.setVisibility(View.GONE);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -81,11 +81,13 @@ class MessageDetailsRecipientAdapter extends BaseAdapter implements AbsListView.
|
|||
|
||||
private final Recipient recipient;
|
||||
private final Status deliveryStatus;
|
||||
private final boolean isUnidentified;
|
||||
private final long timestamp;
|
||||
|
||||
RecipientDeliveryStatus(Recipient recipient, Status deliveryStatus, long timestamp) {
|
||||
RecipientDeliveryStatus(Recipient recipient, Status deliveryStatus, boolean isUnidentified, long timestamp) {
|
||||
this.recipient = recipient;
|
||||
this.deliveryStatus = deliveryStatus;
|
||||
this.isUnidentified = isUnidentified;
|
||||
this.timestamp = timestamp;
|
||||
}
|
||||
|
||||
|
@ -93,6 +95,10 @@ class MessageDetailsRecipientAdapter extends BaseAdapter implements AbsListView.
|
|||
return deliveryStatus;
|
||||
}
|
||||
|
||||
boolean isUnidentified() {
|
||||
return isUnidentified;
|
||||
}
|
||||
|
||||
public long getTimestamp() {
|
||||
return timestamp;
|
||||
}
|
||||
|
|
|
@ -16,13 +16,12 @@
|
|||
*/
|
||||
package org.thoughtcrime.securesms;
|
||||
|
||||
import android.annotation.SuppressLint;
|
||||
import android.content.Context;
|
||||
import android.os.AsyncTask;
|
||||
import android.text.TextUtils;
|
||||
import android.util.AttributeSet;
|
||||
import android.view.View;
|
||||
import android.widget.Button;
|
||||
import android.widget.ImageView;
|
||||
import android.widget.RelativeLayout;
|
||||
import android.widget.TextView;
|
||||
|
||||
|
@ -30,15 +29,13 @@ import org.thoughtcrime.securesms.MessageDetailsRecipientAdapter.RecipientDelive
|
|||
import org.thoughtcrime.securesms.components.AvatarImageView;
|
||||
import org.thoughtcrime.securesms.components.DeliveryStatusView;
|
||||
import org.thoughtcrime.securesms.components.FromTextView;
|
||||
import org.thoughtcrime.securesms.database.DatabaseFactory;
|
||||
import org.thoughtcrime.securesms.database.MmsDatabase;
|
||||
import org.thoughtcrime.securesms.database.documents.IdentityKeyMismatch;
|
||||
import org.thoughtcrime.securesms.database.documents.NetworkFailure;
|
||||
import org.thoughtcrime.securesms.database.model.MessageRecord;
|
||||
import org.thoughtcrime.securesms.mms.GlideRequests;
|
||||
import org.thoughtcrime.securesms.recipients.Recipient;
|
||||
import org.thoughtcrime.securesms.recipients.RecipientModifiedListener;
|
||||
import org.thoughtcrime.securesms.sms.MessageSender;
|
||||
import org.thoughtcrime.securesms.util.TextSecurePreferences;
|
||||
import org.thoughtcrime.securesms.util.Util;
|
||||
|
||||
/**
|
||||
|
@ -58,8 +55,8 @@ public class MessageRecipientListItem extends RelativeLayout
|
|||
private TextView errorDescription;
|
||||
private TextView actionDescription;
|
||||
private Button conflictButton;
|
||||
private Button resendButton;
|
||||
private AvatarImageView contactPhotoImage;
|
||||
private ImageView unidentifiedDeliveryIcon;
|
||||
private DeliveryStatusView deliveryStatusView;
|
||||
|
||||
public MessageRecipientListItem(Context context) {
|
||||
|
@ -73,13 +70,13 @@ public class MessageRecipientListItem extends RelativeLayout
|
|||
@Override
|
||||
protected void onFinishInflate() {
|
||||
super.onFinishInflate();
|
||||
this.fromView = findViewById(R.id.from);
|
||||
this.errorDescription = findViewById(R.id.error_description);
|
||||
this.actionDescription = findViewById(R.id.action_description);
|
||||
this.contactPhotoImage = findViewById(R.id.contact_photo_image);
|
||||
this.conflictButton = findViewById(R.id.conflict_button);
|
||||
this.resendButton = findViewById(R.id.resend_button);
|
||||
this.deliveryStatusView = findViewById(R.id.delivery_status);
|
||||
this.fromView = findViewById(R.id.from);
|
||||
this.errorDescription = findViewById(R.id.error_description);
|
||||
this.actionDescription = findViewById(R.id.action_description);
|
||||
this.contactPhotoImage = findViewById(R.id.contact_photo_image);
|
||||
this.conflictButton = findViewById(R.id.conflict_button);
|
||||
this.unidentifiedDeliveryIcon = findViewById(R.id.ud_indicator);
|
||||
this.deliveryStatusView = findViewById(R.id.delivery_status);
|
||||
}
|
||||
|
||||
public void set(final GlideRequests glideRequests,
|
||||
|
@ -94,6 +91,7 @@ public class MessageRecipientListItem extends RelativeLayout
|
|||
fromView.setText(member.getRecipient());
|
||||
contactPhotoImage.setAvatar(glideRequests, member.getRecipient(), false);
|
||||
setIssueIndicators(record, isPushGroup);
|
||||
unidentifiedDeliveryIcon.setVisibility(TextSecurePreferences.isShowUnidentifiedDeliveryIndicatorsEnabled(getContext()) && member.isUnidentified() ? VISIBLE : GONE);
|
||||
}
|
||||
|
||||
private void setIssueIndicators(final MessageRecord record,
|
||||
|
@ -105,25 +103,13 @@ public class MessageRecipientListItem extends RelativeLayout
|
|||
String errorText = "";
|
||||
|
||||
if (keyMismatch != null) {
|
||||
resendButton.setVisibility(View.GONE);
|
||||
conflictButton.setVisibility(View.VISIBLE);
|
||||
|
||||
errorText = getContext().getString(R.string.MessageDetailsRecipient_new_safety_number);
|
||||
conflictButton.setOnClickListener(v -> new ConfirmIdentityDialog(getContext(), record, keyMismatch).show());
|
||||
} else if (networkFailure != null || (!isPushGroup && record.isFailed())) {
|
||||
resendButton.setVisibility(View.VISIBLE);
|
||||
resendButton.setEnabled(true);
|
||||
resendButton.requestFocus();
|
||||
} else if ((networkFailure != null && !record.isPending()) || (!isPushGroup && record.isFailed())) {
|
||||
conflictButton.setVisibility(View.GONE);
|
||||
|
||||
errorText = getContext().getString(R.string.MessageDetailsRecipient_failed_to_send);
|
||||
resendButton.setOnClickListener(v -> {
|
||||
resendButton.setVisibility(View.GONE);
|
||||
errorDescription.setVisibility(View.GONE);
|
||||
actionDescription.setVisibility(View.VISIBLE);
|
||||
actionDescription.setText(R.string.message_recipients_list_item__resending);
|
||||
new ResendAsyncTask(record, networkFailure).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
|
||||
});
|
||||
} else {
|
||||
if (record.isOutgoing()) {
|
||||
if (member.getDeliveryStatus() == RecipientDeliveryStatus.Status.PENDING || member.getDeliveryStatus() == RecipientDeliveryStatus.Status.UNKNOWN) {
|
||||
|
@ -142,7 +128,6 @@ public class MessageRecipientListItem extends RelativeLayout
|
|||
deliveryStatusView.setVisibility(View.GONE);
|
||||
}
|
||||
|
||||
resendButton.setVisibility(View.GONE);
|
||||
conflictButton.setVisibility(View.GONE);
|
||||
}
|
||||
|
||||
|
@ -183,31 +168,4 @@ public class MessageRecipientListItem extends RelativeLayout
|
|||
contactPhotoImage.setAvatar(glideRequests, recipient, false);
|
||||
});
|
||||
}
|
||||
|
||||
@SuppressLint("StaticFieldLeak")
|
||||
private class ResendAsyncTask extends AsyncTask<Void,Void,Void> {
|
||||
private final Context context;
|
||||
private final MessageRecord record;
|
||||
private final NetworkFailure failure;
|
||||
|
||||
ResendAsyncTask(MessageRecord record, NetworkFailure failure) {
|
||||
this.context = getContext().getApplicationContext();
|
||||
this.record = record;
|
||||
this.failure = failure;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Void doInBackground(Void... params) {
|
||||
MmsDatabase mmsDatabase = DatabaseFactory.getMmsDatabase(context);
|
||||
mmsDatabase.removeFailure(record.getId(), failure);
|
||||
|
||||
if (record.getRecipient().isPushGroupRecipient()) {
|
||||
MessageSender.resendGroupMessage(context, record, failure.getAddress());
|
||||
} else {
|
||||
MessageSender.resend(context, record);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -7,9 +7,8 @@ import android.support.v7.widget.SwitchCompat;
|
|||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.TextView;
|
||||
|
||||
import org.thoughtcrime.securesms.jobs.MultiDeviceReadReceiptUpdateJob;
|
||||
import org.thoughtcrime.securesms.jobs.MultiDeviceConfigurationUpdateJob;
|
||||
import org.thoughtcrime.securesms.util.TextSecurePreferences;
|
||||
import org.thoughtcrime.securesms.util.ViewUtil;
|
||||
|
||||
|
@ -39,7 +38,9 @@ public class ReadReceiptsIntroFragment extends Fragment {
|
|||
TextSecurePreferences.setReadReceiptsEnabled(getContext(), isChecked);
|
||||
ApplicationContext.getInstance(getContext())
|
||||
.getJobManager()
|
||||
.add(new MultiDeviceReadReceiptUpdateJob(getContext(), isChecked));
|
||||
.add(new MultiDeviceConfigurationUpdateJob(getContext(),
|
||||
isChecked,
|
||||
TextSecurePreferences.isShowUnidentifiedDeliveryIndicatorsEnabled(getContext())));
|
||||
});
|
||||
|
||||
return v;
|
||||
|
|
|
@ -30,6 +30,7 @@ import android.telephony.PhoneNumberUtils;
|
|||
|
||||
import org.thoughtcrime.securesms.components.SwitchPreferenceCompat;
|
||||
import org.thoughtcrime.securesms.database.GroupDatabase;
|
||||
import org.thoughtcrime.securesms.jobs.RotateProfileKeyJob;
|
||||
import org.thoughtcrime.securesms.logging.Log;
|
||||
import android.util.Pair;
|
||||
import android.view.MenuItem;
|
||||
|
@ -740,6 +741,12 @@ public class RecipientPreferenceActivity extends PassphraseRequiredActionBarActi
|
|||
}
|
||||
}
|
||||
|
||||
if (blocked && (recipient.resolve().isSystemContact() || recipient.resolve().isProfileSharing())) {
|
||||
ApplicationContext.getInstance(context)
|
||||
.getJobManager()
|
||||
.add(new RotateProfileKeyJob(context));
|
||||
}
|
||||
|
||||
ApplicationContext.getInstance(context)
|
||||
.getJobManager()
|
||||
.add(new MultiDeviceBlockedUpdateJob(context));
|
||||
|
|
|
@ -31,4 +31,8 @@ public class ProfileKeyUtil {
|
|||
}
|
||||
}
|
||||
|
||||
public static synchronized @NonNull byte[] rotateProfileKey(@NonNull Context context) {
|
||||
TextSecurePreferences.setProfileKey(context, null);
|
||||
return getProfileKey(context);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -10,6 +10,7 @@ import android.util.Log;
|
|||
import org.signal.libsignal.metadata.certificate.CertificateValidator;
|
||||
import org.signal.libsignal.metadata.certificate.InvalidCertificateException;
|
||||
import org.thoughtcrime.securesms.BuildConfig;
|
||||
import org.thoughtcrime.securesms.database.RecipientDatabase;
|
||||
import org.thoughtcrime.securesms.recipients.Recipient;
|
||||
import org.thoughtcrime.securesms.util.Base64;
|
||||
import org.thoughtcrime.securesms.util.TextSecurePreferences;
|
||||
|
@ -40,6 +41,11 @@ public class UnidentifiedAccessUtil {
|
|||
public static Optional<UnidentifiedAccessPair> getAccessFor(@NonNull Context context,
|
||||
@NonNull Recipient recipient)
|
||||
{
|
||||
if (!TextSecurePreferences.isUnidentifiedDeliveryEnabled(context)) {
|
||||
Log.i(TAG, "Unidentified delivery is disabled. [other]");
|
||||
return Optional.absent();
|
||||
}
|
||||
|
||||
try {
|
||||
byte[] theirUnidentifiedAccessKey = getTargetUnidentifiedAccessKey(recipient);
|
||||
byte[] ourUnidentifiedAccessKey = getSelfUnidentifiedAccessKey(context);
|
||||
|
@ -49,9 +55,9 @@ public class UnidentifiedAccessUtil {
|
|||
ourUnidentifiedAccessKey = Util.getSecretBytes(16);
|
||||
}
|
||||
|
||||
Log.w(TAG, "Their access key: " + (theirUnidentifiedAccessKey == null));
|
||||
Log.w(TAG, "Our access key: " + (ourUnidentifiedAccessKey == null));
|
||||
Log.w(TAG, "Our certificatE: " + (ourUnidentifiedAccessCertificate == null));
|
||||
Log.i(TAG, "Their access key present? " + (theirUnidentifiedAccessKey != null));
|
||||
Log.i(TAG, "Our access key present? " + (ourUnidentifiedAccessKey != null));
|
||||
Log.i(TAG, "Our certificate present? " + (ourUnidentifiedAccessCertificate != null));
|
||||
|
||||
if (theirUnidentifiedAccessKey != null &&
|
||||
ourUnidentifiedAccessKey != null &&
|
||||
|
@ -71,6 +77,11 @@ public class UnidentifiedAccessUtil {
|
|||
}
|
||||
|
||||
public static Optional<UnidentifiedAccessPair> getAccessForSync(@NonNull Context context) {
|
||||
if (!TextSecurePreferences.isUnidentifiedDeliveryEnabled(context)) {
|
||||
Log.i(TAG, "Unidentified delivery is disabled. [self]");
|
||||
return Optional.absent();
|
||||
}
|
||||
|
||||
try {
|
||||
byte[] ourUnidentifiedAccessKey = getSelfUnidentifiedAccessKey(context);
|
||||
byte[] ourUnidentifiedAccessCertificate = TextSecurePreferences.getUnidentifiedAccessCertificate(context);
|
||||
|
|
|
@ -34,6 +34,7 @@ public abstract class MessagingDatabase extends Database implements MmsSmsColumn
|
|||
public abstract void markExpireStarted(long messageId, long startTime);
|
||||
|
||||
public abstract void markAsSent(long messageId, boolean secure);
|
||||
public abstract void markUnidentified(long messageId, boolean unidentified);
|
||||
|
||||
public void setMismatchedIdentity(long messageId, final Address address, final IdentityKey identityKey) {
|
||||
List<IdentityKeyMismatch> items = new ArrayList<IdentityKeyMismatch>() {{
|
||||
|
|
|
@ -343,11 +343,11 @@ public class MmsDatabase extends MessagingDatabase {
|
|||
notifyConversationListeners(threadId);
|
||||
}
|
||||
|
||||
// public void markAsSending(long messageId) {
|
||||
// long threadId = getThreadIdForMessage(messageId);
|
||||
// updateMailboxBitmask(messageId, Types.BASE_TYPE_MASK, Types.BASE_SENDING_TYPE, Optional.of(threadId));
|
||||
// notifyConversationListeners(threadId);
|
||||
// }
|
||||
public void markAsSending(long messageId) {
|
||||
long threadId = getThreadIdForMessage(messageId);
|
||||
updateMailboxBitmask(messageId, Types.BASE_TYPE_MASK, Types.BASE_SENDING_TYPE, Optional.of(threadId));
|
||||
notifyConversationListeners(threadId);
|
||||
}
|
||||
|
||||
public void markAsSentFailed(long messageId) {
|
||||
long threadId = getThreadIdForMessage(messageId);
|
||||
|
@ -403,6 +403,7 @@ public class MmsDatabase extends MessagingDatabase {
|
|||
notifyConversationListeners(threadId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void markUnidentified(long messageId, boolean unidentified) {
|
||||
ContentValues contentValues = new ContentValues();
|
||||
contentValues.put(UNIDENTIFIED, unidentified ? 1 : 0);
|
||||
|
|
|
@ -270,8 +270,7 @@ public class MmsSmsDatabase extends Database {
|
|||
MmsDatabase.QUOTE_BODY,
|
||||
MmsDatabase.QUOTE_MISSING,
|
||||
MmsDatabase.QUOTE_ATTACHMENT,
|
||||
MmsDatabase.SHARED_CONTACTS,
|
||||
MmsDatabase.UNIDENTIFIED};
|
||||
MmsDatabase.SHARED_CONTACTS};
|
||||
|
||||
SQLiteQueryBuilder mmsQueryBuilder = new SQLiteQueryBuilder();
|
||||
SQLiteQueryBuilder smsQueryBuilder = new SQLiteQueryBuilder();
|
||||
|
|
|
@ -239,10 +239,15 @@ public class SmsDatabase extends MessagingDatabase {
|
|||
updateTypeBitmask(id, Types.BASE_TYPE_MASK, Types.BASE_SENT_TYPE | (isSecure ? Types.PUSH_MESSAGE_BIT | Types.SECURE_MESSAGE_BIT : 0));
|
||||
}
|
||||
|
||||
public void markAsSending(long id) {
|
||||
updateTypeBitmask(id, Types.BASE_TYPE_MASK, Types.BASE_SENDING_TYPE);
|
||||
}
|
||||
|
||||
public void markAsMissedCall(long id) {
|
||||
updateTypeBitmask(id, Types.TOTAL_MASK, Types.MISSED_CALL_TYPE);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void markUnidentified(long id, boolean unidentified) {
|
||||
ContentValues contentValues = new ContentValues(1);
|
||||
contentValues.put(UNIDENTIFIED, unidentified ? 1 : 0);
|
||||
|
@ -695,7 +700,9 @@ public class SmsDatabase extends MessagingDatabase {
|
|||
|
||||
public Cursor getMessageCursor(long messageId) {
|
||||
SQLiteDatabase db = databaseHelper.getReadableDatabase();
|
||||
return db.query(TABLE_NAME, MESSAGE_PROJECTION, ID_WHERE, new String[] {messageId + ""}, null, null, null);
|
||||
Cursor cursor = db.query(TABLE_NAME, MESSAGE_PROJECTION, ID_WHERE, new String[] {messageId + ""}, null, null, null);
|
||||
setNotifyConverationListeners(cursor, getThreadIdForMessage(messageId));
|
||||
return cursor;
|
||||
}
|
||||
|
||||
public boolean deleteMessage(long messageId) {
|
||||
|
|
|
@ -289,6 +289,9 @@ public class SQLCipherOpenHelper extends SQLiteOpenHelper {
|
|||
db.execSQL("ALTER TABLE recipient_preferences ADD COLUMN unidentified_access_mode INTEGER DEFAULT 0");
|
||||
db.execSQL("ALTER TABLE push ADD COLUMN server_timestamp INTEGER DEFAULT 0");
|
||||
db.execSQL("ALTER TABLE push ADD COLUMN server_guid TEXT DEFAULT NULL");
|
||||
db.execSQL("ALTER TABLE group_receipts ADD COLUMN unidentified INTEGER DEFAULT 0");
|
||||
db.execSQL("ALTER TABLE mms ADD COLUMN unidentified INTEGER DEFAULT 0");
|
||||
db.execSQL("ALTER TABLE sms ADD COLUMN unidentified INTEGER DEFAULT 0");
|
||||
}
|
||||
|
||||
db.setTransactionSuccessful();
|
||||
|
|
|
@ -3,6 +3,9 @@ package org.thoughtcrime.securesms.dependencies;
|
|||
import android.content.Context;
|
||||
|
||||
import org.thoughtcrime.securesms.gcm.GcmBroadcastReceiver;
|
||||
import org.thoughtcrime.securesms.jobs.MultiDeviceConfigurationUpdateJob;
|
||||
import org.thoughtcrime.securesms.jobs.RefreshUnidentifiedDeliveryAbilityJob;
|
||||
import org.thoughtcrime.securesms.jobs.RotateProfileKeyJob;
|
||||
import org.thoughtcrime.securesms.logging.Log;
|
||||
|
||||
import org.greenrobot.eventbus.EventBus;
|
||||
|
@ -87,7 +90,10 @@ import dagger.Provides;
|
|||
AppProtectionPreferenceFragment.class,
|
||||
GcmBroadcastReceiver.class,
|
||||
RotateCertificateJob.class,
|
||||
SendDeliveryReceiptJob.class})
|
||||
SendDeliveryReceiptJob.class,
|
||||
RotateProfileKeyJob.class,
|
||||
MultiDeviceConfigurationUpdateJob.class,
|
||||
RefreshUnidentifiedDeliveryAbilityJob.class})
|
||||
public class SignalCommunicationModule {
|
||||
|
||||
private static final String TAG = SignalCommunicationModule.class.getSimpleName();
|
||||
|
|
|
@ -2,6 +2,7 @@ package org.thoughtcrime.securesms.jobs;
|
|||
|
||||
import android.content.Context;
|
||||
import android.support.annotation.NonNull;
|
||||
import android.util.Log;
|
||||
|
||||
import org.thoughtcrime.securesms.crypto.MasterSecret;
|
||||
import org.thoughtcrime.securesms.crypto.UnidentifiedAccessUtil;
|
||||
|
@ -13,6 +14,8 @@ import org.thoughtcrime.securesms.jobmanager.JobParameters;
|
|||
import org.thoughtcrime.securesms.jobmanager.SafeData;
|
||||
import org.thoughtcrime.securesms.recipients.Recipient;
|
||||
import org.thoughtcrime.securesms.util.GroupUtil;
|
||||
import org.thoughtcrime.securesms.util.TextSecurePreferences;
|
||||
import org.whispersystems.libsignal.util.guava.Optional;
|
||||
import org.whispersystems.signalservice.api.SignalServiceMessageSender;
|
||||
import org.whispersystems.signalservice.api.crypto.UntrustedIdentityException;
|
||||
import org.whispersystems.signalservice.api.messages.multidevice.BlockedListMessage;
|
||||
|
@ -61,6 +64,11 @@ public class MultiDeviceBlockedUpdateJob extends MasterSecretJob implements Inje
|
|||
public void onRun(MasterSecret masterSecret)
|
||||
throws IOException, UntrustedIdentityException
|
||||
{
|
||||
if (!TextSecurePreferences.isMultiDevice(context)) {
|
||||
Log.i(TAG, "Not multi device, aborting...");
|
||||
return;
|
||||
}
|
||||
|
||||
RecipientDatabase database = DatabaseFactory.getRecipientDatabase(context);
|
||||
|
||||
try (RecipientReader reader = database.readerForBlocked(database.getBlocked())) {
|
||||
|
|
|
@ -0,0 +1,87 @@
|
|||
package org.thoughtcrime.securesms.jobs;
|
||||
|
||||
|
||||
import android.content.Context;
|
||||
import android.support.annotation.NonNull;
|
||||
|
||||
import org.thoughtcrime.securesms.crypto.UnidentifiedAccessUtil;
|
||||
import org.thoughtcrime.securesms.dependencies.InjectableType;
|
||||
import org.thoughtcrime.securesms.jobmanager.JobParameters;
|
||||
import org.thoughtcrime.securesms.jobmanager.SafeData;
|
||||
import org.thoughtcrime.securesms.logging.Log;
|
||||
import org.thoughtcrime.securesms.util.TextSecurePreferences;
|
||||
import org.whispersystems.libsignal.util.guava.Optional;
|
||||
import org.whispersystems.signalservice.api.SignalServiceMessageSender;
|
||||
import org.whispersystems.signalservice.api.crypto.UntrustedIdentityException;
|
||||
import org.whispersystems.signalservice.api.messages.multidevice.ConfigurationMessage;
|
||||
import org.whispersystems.signalservice.api.messages.multidevice.SignalServiceSyncMessage;
|
||||
import org.whispersystems.signalservice.api.push.exceptions.PushNetworkException;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import javax.inject.Inject;
|
||||
|
||||
import androidx.work.Data;
|
||||
|
||||
public class MultiDeviceConfigurationUpdateJob extends ContextJob implements InjectableType {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
private static final String TAG = MultiDeviceConfigurationUpdateJob.class.getSimpleName();
|
||||
|
||||
private static final String KEY_READ_RECEIPTS_ENABLED = "read_receipts_enabled";
|
||||
private static final String KEY_UNIDENTIFIED_DELIVERY_INDICATORS_ENABLED = "unidentified_delivery_indicators_enabled";
|
||||
|
||||
@Inject transient SignalServiceMessageSender messageSender;
|
||||
|
||||
private boolean readReceiptsEnabled;
|
||||
private boolean unidentifiedDeliveryIndicatorsEnabled;
|
||||
|
||||
public MultiDeviceConfigurationUpdateJob() {
|
||||
super(null, null);
|
||||
}
|
||||
|
||||
public MultiDeviceConfigurationUpdateJob(Context context, boolean readReceiptsEnabled, boolean unidentifiedDeliveryIndicatorsEnabled) {
|
||||
super(context, JobParameters.newBuilder()
|
||||
.withGroupId("__MULTI_DEVICE_CONFIGURATION_UPDATE_JOB__")
|
||||
.withNetworkRequirement()
|
||||
.create());
|
||||
|
||||
this.readReceiptsEnabled = readReceiptsEnabled;
|
||||
this.unidentifiedDeliveryIndicatorsEnabled = unidentifiedDeliveryIndicatorsEnabled;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void initialize(@NonNull SafeData data) {
|
||||
readReceiptsEnabled = data.getBoolean(KEY_READ_RECEIPTS_ENABLED);
|
||||
unidentifiedDeliveryIndicatorsEnabled = data.getBoolean(KEY_UNIDENTIFIED_DELIVERY_INDICATORS_ENABLED);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected @NonNull Data serialize(@NonNull Data.Builder dataBuilder) {
|
||||
return dataBuilder.putBoolean(KEY_READ_RECEIPTS_ENABLED, readReceiptsEnabled)
|
||||
.putBoolean(KEY_UNIDENTIFIED_DELIVERY_INDICATORS_ENABLED, unidentifiedDeliveryIndicatorsEnabled)
|
||||
.build();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onRun() throws IOException, UntrustedIdentityException {
|
||||
if (!TextSecurePreferences.isMultiDevice(context)) {
|
||||
Log.i(TAG, "Not multi device, aborting...");
|
||||
return;
|
||||
}
|
||||
|
||||
messageSender.sendMessage(SignalServiceSyncMessage.forConfiguration(new ConfigurationMessage(Optional.of(readReceiptsEnabled), Optional.of(unidentifiedDeliveryIndicatorsEnabled))),
|
||||
UnidentifiedAccessUtil.getAccessForSync(context));
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onShouldRetry(Exception e) {
|
||||
return e instanceof PushNetworkException;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCanceled() {
|
||||
Log.w(TAG, "**** Failed to synchronize read receipts state!");
|
||||
}
|
||||
}
|
|
@ -116,7 +116,7 @@ public class MultiDeviceContactUpdateJob extends MasterSecretJob implements Inje
|
|||
throws IOException, UntrustedIdentityException, NetworkException
|
||||
{
|
||||
if (!TextSecurePreferences.isMultiDevice(context)) {
|
||||
Log.w(TAG, "Not multi device, aborting...");
|
||||
Log.i(TAG, "Not multi device, aborting...");
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
|
@ -15,6 +15,7 @@ import org.thoughtcrime.securesms.logging.Log;
|
|||
import org.thoughtcrime.securesms.recipients.Recipient;
|
||||
import org.thoughtcrime.securesms.util.GroupUtil;
|
||||
import org.thoughtcrime.securesms.jobmanager.JobParameters;
|
||||
import org.thoughtcrime.securesms.util.TextSecurePreferences;
|
||||
import org.whispersystems.libsignal.util.guava.Optional;
|
||||
import org.whispersystems.signalservice.api.SignalServiceMessageSender;
|
||||
import org.whispersystems.signalservice.api.crypto.UntrustedIdentityException;
|
||||
|
@ -67,6 +68,11 @@ public class MultiDeviceGroupUpdateJob extends MasterSecretJob implements Inject
|
|||
|
||||
@Override
|
||||
public void onRun(MasterSecret masterSecret) throws Exception {
|
||||
if (!TextSecurePreferences.isMultiDevice(context)) {
|
||||
Log.i(TAG, "Not multi device, aborting...");
|
||||
return;
|
||||
}
|
||||
|
||||
File contactDataFile = createTempFile("multidevice-contact-update");
|
||||
GroupDatabase.Reader reader = null;
|
||||
|
||||
|
|
|
@ -62,7 +62,7 @@ public class MultiDeviceProfileKeyUpdateJob extends MasterSecretJob implements I
|
|||
@Override
|
||||
public void onRun(MasterSecret masterSecret) throws IOException, UntrustedIdentityException {
|
||||
if (!TextSecurePreferences.isMultiDevice(getContext())) {
|
||||
Log.w(TAG, "Not multi device...");
|
||||
Log.i(TAG, "Not multi device...");
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
|
@ -9,6 +9,7 @@ import org.thoughtcrime.securesms.dependencies.InjectableType;
|
|||
import org.thoughtcrime.securesms.jobmanager.JobParameters;
|
||||
import org.thoughtcrime.securesms.jobmanager.SafeData;
|
||||
import org.thoughtcrime.securesms.logging.Log;
|
||||
import org.thoughtcrime.securesms.util.TextSecurePreferences;
|
||||
import org.whispersystems.libsignal.util.guava.Optional;
|
||||
import org.whispersystems.signalservice.api.SignalServiceMessageSender;
|
||||
import org.whispersystems.signalservice.api.crypto.UntrustedIdentityException;
|
||||
|
@ -22,6 +23,10 @@ import javax.inject.Inject;
|
|||
|
||||
import androidx.work.Data;
|
||||
|
||||
/**
|
||||
* Use {@link MultiDeviceConfigurationUpdateJob}.
|
||||
*/
|
||||
@Deprecated
|
||||
public class MultiDeviceReadReceiptUpdateJob extends ContextJob implements InjectableType {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
@ -59,7 +64,12 @@ public class MultiDeviceReadReceiptUpdateJob extends ContextJob implements Injec
|
|||
|
||||
@Override
|
||||
public void onRun() throws IOException, UntrustedIdentityException {
|
||||
messageSender.sendMessage(SignalServiceSyncMessage.forConfiguration(new ConfigurationMessage(Optional.of(enabled))),
|
||||
if (!TextSecurePreferences.isMultiDevice(context)) {
|
||||
Log.i(TAG, "Not multi device, aborting...");
|
||||
return;
|
||||
}
|
||||
|
||||
messageSender.sendMessage(SignalServiceSyncMessage.forConfiguration(new ConfigurationMessage(Optional.of(enabled), Optional.absent())),
|
||||
UnidentifiedAccessUtil.getAccessForSync(context));
|
||||
}
|
||||
|
||||
|
|
|
@ -15,6 +15,7 @@ import org.thoughtcrime.securesms.dependencies.InjectableType;
|
|||
import org.thoughtcrime.securesms.jobmanager.JobParameters;
|
||||
import org.thoughtcrime.securesms.util.JsonUtils;
|
||||
import org.thoughtcrime.securesms.util.TextSecurePreferences;
|
||||
import org.whispersystems.libsignal.util.guava.Optional;
|
||||
import org.whispersystems.signalservice.api.SignalServiceMessageSender;
|
||||
import org.whispersystems.signalservice.api.crypto.UntrustedIdentityException;
|
||||
import org.whispersystems.signalservice.api.messages.multidevice.ReadMessage;
|
||||
|
@ -91,7 +92,7 @@ public class MultiDeviceReadUpdateJob extends MasterSecretJob implements Injecta
|
|||
@Override
|
||||
public void onRun(MasterSecret masterSecret) throws IOException, UntrustedIdentityException {
|
||||
if (!TextSecurePreferences.isMultiDevice(context)) {
|
||||
Log.w(TAG, "Not multi device...");
|
||||
Log.i(TAG, "Not multi device...");
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -101,8 +102,7 @@ public class MultiDeviceReadUpdateJob extends MasterSecretJob implements Injecta
|
|||
readMessages.add(new ReadMessage(messageId.sender, messageId.timestamp));
|
||||
}
|
||||
|
||||
messageSender.sendMessage(SignalServiceSyncMessage.forRead(readMessages),
|
||||
UnidentifiedAccessUtil.getAccessForSync(context));
|
||||
messageSender.sendMessage(SignalServiceSyncMessage.forRead(readMessages), UnidentifiedAccessUtil.getAccessForSync(context));
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -91,7 +91,7 @@ public class MultiDeviceVerifiedUpdateJob extends ContextJob implements Injectab
|
|||
public void onRun() throws IOException, UntrustedIdentityException {
|
||||
try {
|
||||
if (!TextSecurePreferences.isMultiDevice(context)) {
|
||||
Log.w(TAG, "Not multi device...");
|
||||
Log.i(TAG, "Not multi device...");
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
|
@ -20,6 +20,7 @@ import org.signal.libsignal.metadata.ProtocolInvalidVersionException;
|
|||
import org.signal.libsignal.metadata.ProtocolLegacyMessageException;
|
||||
import org.signal.libsignal.metadata.ProtocolNoSessionException;
|
||||
import org.signal.libsignal.metadata.ProtocolUntrustedIdentityException;
|
||||
import org.signal.libsignal.metadata.SelfSendException;
|
||||
import org.thoughtcrime.securesms.ApplicationContext;
|
||||
import org.thoughtcrime.securesms.ConversationListActivity;
|
||||
import org.thoughtcrime.securesms.R;
|
||||
|
@ -36,6 +37,7 @@ import org.thoughtcrime.securesms.crypto.storage.TextSecureSessionStore;
|
|||
import org.thoughtcrime.securesms.database.Address;
|
||||
import org.thoughtcrime.securesms.database.DatabaseFactory;
|
||||
import org.thoughtcrime.securesms.database.GroupDatabase;
|
||||
import org.thoughtcrime.securesms.database.GroupReceiptDatabase;
|
||||
import org.thoughtcrime.securesms.database.MessagingDatabase;
|
||||
import org.thoughtcrime.securesms.database.MessagingDatabase.InsertResult;
|
||||
import org.thoughtcrime.securesms.database.MessagingDatabase.SyncMessageId;
|
||||
|
@ -242,6 +244,8 @@ public class PushDecryptJob extends ContextJob {
|
|||
handleNeedsDeliveryReceipt(content, message);
|
||||
}
|
||||
} else if (content.getSyncMessage().isPresent()) {
|
||||
TextSecurePreferences.setMultiDevice(context, true);
|
||||
|
||||
SignalServiceSyncMessage syncMessage = content.getSyncMessage().get();
|
||||
|
||||
if (syncMessage.getSent().isPresent()) handleSynchronizeSentMessage(content, syncMessage.getSent().get());
|
||||
|
@ -273,7 +277,11 @@ public class PushDecryptJob extends ContextJob {
|
|||
} catch (ProtocolInvalidVersionException e) {
|
||||
Log.w(TAG, e);
|
||||
handleInvalidVersionMessage(e.getSender(), e.getSenderDevice(), envelope.getTimestamp(), smsMessageId);
|
||||
} catch (ProtocolInvalidMessageException | ProtocolInvalidKeyIdException | ProtocolInvalidKeyException | ProtocolUntrustedIdentityException e) {
|
||||
} catch (ProtocolInvalidMessageException e) {
|
||||
Log.w(TAG, e);
|
||||
handleCorruptMessage(e.getSender(), e.getSenderDevice(), envelope.getTimestamp(), smsMessageId);
|
||||
}
|
||||
catch (ProtocolInvalidKeyIdException | ProtocolInvalidKeyException | ProtocolUntrustedIdentityException e) {
|
||||
Log.w(TAG, e);
|
||||
handleCorruptMessage(e.getSender(), e.getSenderDevice(), envelope.getTimestamp(), smsMessageId);
|
||||
} catch (StorageFailedException e) {
|
||||
|
@ -290,6 +298,8 @@ public class PushDecryptJob extends ContextJob {
|
|||
handleDuplicateMessage(e.getSender(), e.getSenderDevice(), envelope.getTimestamp(), smsMessageId);
|
||||
} catch (InvalidMetadataVersionException | InvalidMetadataMessageException e) {
|
||||
Log.w(TAG, e);
|
||||
} catch (SelfSendException e) {
|
||||
Log.i(TAG, "Dropping UD message from self.");
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -542,6 +552,10 @@ public class PushDecryptJob extends ContextJob {
|
|||
ApplicationContext.getInstance(context)
|
||||
.getJobManager()
|
||||
.add(new MultiDeviceContactUpdateJob(getContext(), true));
|
||||
|
||||
ApplicationContext.getInstance(context)
|
||||
.getJobManager()
|
||||
.add(new RefreshUnidentifiedDeliveryAbilityJob(context));
|
||||
}
|
||||
|
||||
if (message.isGroupsRequest()) {
|
||||
|
@ -559,7 +573,9 @@ public class PushDecryptJob extends ContextJob {
|
|||
if (message.isConfigurationRequest()) {
|
||||
ApplicationContext.getInstance(context)
|
||||
.getJobManager()
|
||||
.add(new MultiDeviceReadReceiptUpdateJob(getContext(), TextSecurePreferences.isReadReceiptsEnabled(getContext())));
|
||||
.add(new MultiDeviceConfigurationUpdateJob(getContext(),
|
||||
TextSecurePreferences.isReadReceiptsEnabled(getContext()),
|
||||
TextSecurePreferences.isShowUnidentifiedDeliveryIndicatorsEnabled(getContext())));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -670,7 +686,17 @@ public class PushDecryptJob extends ContextJob {
|
|||
long threadId = DatabaseFactory.getThreadDatabase(context).getThreadIdFor(recipients);
|
||||
long messageId = database.insertMessageOutbox(mediaMessage, threadId, false, null);
|
||||
|
||||
if (recipients.getAddress().isGroup()) {
|
||||
GroupReceiptDatabase receiptDatabase = DatabaseFactory.getGroupReceiptDatabase(context);
|
||||
List<Recipient> members = DatabaseFactory.getGroupDatabase(context).getGroupMembers(recipients.getAddress().toGroupString(), false);
|
||||
|
||||
for (Recipient member : members) {
|
||||
receiptDatabase.setUnidentified(member.getAddress(), messageId, message.isUnidentified(member.getAddress().serialize()));
|
||||
}
|
||||
}
|
||||
|
||||
database.markAsSent(messageId, true);
|
||||
database.markUnidentified(messageId, message.isUnidentified(recipients.getAddress().serialize()));
|
||||
|
||||
for (DatabaseAttachment attachment : DatabaseFactory.getAttachmentDatabase(context).getAttachmentsForMessage(messageId)) {
|
||||
ApplicationContext.getInstance(context)
|
||||
|
@ -753,11 +779,19 @@ public class PushDecryptJob extends ContextJob {
|
|||
|
||||
messageId = DatabaseFactory.getMmsDatabase(context).insertMessageOutbox(outgoingMediaMessage, threadId, false, null);
|
||||
database = DatabaseFactory.getMmsDatabase(context);
|
||||
|
||||
GroupReceiptDatabase receiptDatabase = DatabaseFactory.getGroupReceiptDatabase(context);
|
||||
List<Recipient> members = DatabaseFactory.getGroupDatabase(context).getGroupMembers(recipient.getAddress().toGroupString(), false);
|
||||
|
||||
for (Recipient member : members) {
|
||||
receiptDatabase.setUnidentified(member.getAddress(), messageId, message.isUnidentified(member.getAddress().serialize()));
|
||||
}
|
||||
} else {
|
||||
OutgoingTextMessage outgoingTextMessage = new OutgoingEncryptedMessage(recipient, body, expiresInMillis);
|
||||
|
||||
messageId = DatabaseFactory.getSmsDatabase(context).insertMessageOutbox(threadId, outgoingTextMessage, false, message.getTimestamp(), null);
|
||||
database = DatabaseFactory.getSmsDatabase(context);
|
||||
database.markUnidentified(messageId, message.isUnidentified(recipient.getAddress().serialize()));
|
||||
}
|
||||
|
||||
database.markAsSent(messageId, true);
|
||||
|
|
|
@ -45,6 +45,7 @@ import org.whispersystems.signalservice.api.util.InvalidNumberException;
|
|||
import org.whispersystems.signalservice.internal.push.SignalServiceProtos.GroupContext;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
@ -99,6 +100,11 @@ public class PushGroupSendJob extends PushSendJob implements InjectableType {
|
|||
.build();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onAdded() {
|
||||
DatabaseFactory.getMmsDatabase(context).markAsSending(messageId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPushSend()
|
||||
throws IOException, MmsException, NoSuchMessageException, RetryLaterException
|
||||
|
@ -110,6 +116,7 @@ public class PushGroupSendJob extends PushSendJob implements InjectableType {
|
|||
|
||||
try {
|
||||
Log.i(TAG, "Sending message: " + messageId);
|
||||
|
||||
List<Address> target;
|
||||
|
||||
if (filterAddress != null) target = Collections.singletonList(Address.fromSerialized(filterAddress));
|
||||
|
|
|
@ -10,16 +10,19 @@ import org.thoughtcrime.securesms.database.Address;
|
|||
import org.thoughtcrime.securesms.database.DatabaseFactory;
|
||||
import org.thoughtcrime.securesms.database.MmsDatabase;
|
||||
import org.thoughtcrime.securesms.database.NoSuchMessageException;
|
||||
import org.thoughtcrime.securesms.database.RecipientDatabase.UnidentifiedAccessMode;
|
||||
import org.thoughtcrime.securesms.dependencies.InjectableType;
|
||||
import org.thoughtcrime.securesms.jobmanager.SafeData;
|
||||
import org.thoughtcrime.securesms.logging.Log;
|
||||
import org.thoughtcrime.securesms.mms.MediaConstraints;
|
||||
import org.thoughtcrime.securesms.mms.MmsException;
|
||||
import org.thoughtcrime.securesms.mms.OutgoingMediaMessage;
|
||||
import org.thoughtcrime.securesms.recipients.Recipient;
|
||||
import org.thoughtcrime.securesms.service.ExpiringMessageManager;
|
||||
import org.thoughtcrime.securesms.transport.InsecureFallbackApprovalException;
|
||||
import org.thoughtcrime.securesms.transport.RetryLaterException;
|
||||
import org.thoughtcrime.securesms.transport.UndeliverableMessageException;
|
||||
import org.thoughtcrime.securesms.util.TextSecurePreferences;
|
||||
import org.whispersystems.libsignal.util.guava.Optional;
|
||||
import org.whispersystems.signalservice.api.SignalServiceMessageSender;
|
||||
import org.whispersystems.signalservice.api.crypto.UntrustedIdentityException;
|
||||
|
@ -68,6 +71,11 @@ public class PushMediaSendJob extends PushSendJob implements InjectableType {
|
|||
return dataBuilder.putLong(KEY_MESSAGE_ID, messageId).build();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onAdded() {
|
||||
DatabaseFactory.getMmsDatabase(context).markAsSending(messageId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPushSend()
|
||||
throws RetryLaterException, MmsException, NoSuchMessageException,
|
||||
|
@ -85,6 +93,19 @@ public class PushMediaSendJob extends PushSendJob implements InjectableType {
|
|||
markAttachmentsUploaded(messageId, message.getAttachments());
|
||||
database.markUnidentified(messageId, unidentified);
|
||||
|
||||
if (TextSecurePreferences.isUnidentifiedDeliveryEnabled(context)) {
|
||||
Recipient recipient = message.getRecipient().resolve();
|
||||
UnidentifiedAccessMode accessMode = recipient.getUnidentifiedAccessMode();
|
||||
|
||||
if (unidentified && (accessMode == UnidentifiedAccessMode.UNKNOWN || accessMode == UnidentifiedAccessMode.DISABLED)) {
|
||||
Log.i(TAG, "Marking recipient as UD-enabled following a UD send.");
|
||||
DatabaseFactory.getRecipientDatabase(context).setUnidentifiedAccessMode(recipient, UnidentifiedAccessMode.ENABLED);
|
||||
} else if (!unidentified && accessMode != UnidentifiedAccessMode.DISABLED) {
|
||||
Log.i(TAG, "Marking recipient as UD-disabled following a non-UD send.");
|
||||
DatabaseFactory.getRecipientDatabase(context).setUnidentifiedAccessMode(recipient, UnidentifiedAccessMode.DISABLED);
|
||||
}
|
||||
}
|
||||
|
||||
if (message.getExpiresIn() > 0 && !message.isExpirationUpdate()) {
|
||||
database.markExpireStarted(messageId);
|
||||
expirationManager.scheduleDeletion(messageId, true, message.getExpiresIn());
|
||||
|
|
|
@ -3,6 +3,7 @@ package org.thoughtcrime.securesms.jobs;
|
|||
import android.content.Context;
|
||||
import android.support.annotation.NonNull;
|
||||
|
||||
import org.thoughtcrime.securesms.database.RecipientDatabase.UnidentifiedAccessMode;
|
||||
import org.thoughtcrime.securesms.jobmanager.SafeData;
|
||||
import org.thoughtcrime.securesms.logging.Log;
|
||||
|
||||
|
@ -19,11 +20,11 @@ import org.thoughtcrime.securesms.recipients.Recipient;
|
|||
import org.thoughtcrime.securesms.service.ExpiringMessageManager;
|
||||
import org.thoughtcrime.securesms.transport.InsecureFallbackApprovalException;
|
||||
import org.thoughtcrime.securesms.transport.RetryLaterException;
|
||||
import org.thoughtcrime.securesms.util.TextSecurePreferences;
|
||||
import org.whispersystems.libsignal.util.guava.Optional;
|
||||
import org.whispersystems.signalservice.api.SignalServiceMessageSender;
|
||||
import org.whispersystems.signalservice.api.crypto.UnidentifiedAccessPair;
|
||||
import org.whispersystems.signalservice.api.crypto.UntrustedIdentityException;
|
||||
import org.whispersystems.signalservice.api.messages.SendMessageResult;
|
||||
import org.whispersystems.signalservice.api.messages.SignalServiceDataMessage;
|
||||
import org.whispersystems.signalservice.api.push.SignalServiceAddress;
|
||||
import org.whispersystems.signalservice.api.push.exceptions.UnregisteredUserException;
|
||||
|
@ -68,6 +69,7 @@ public class PushTextSendJob extends PushSendJob implements InjectableType {
|
|||
@Override
|
||||
public void onAdded() {
|
||||
Log.i(TAG, "onAdded() messageId: " + messageId);
|
||||
DatabaseFactory.getSmsDatabase(context).markAsSending(messageId);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -83,6 +85,19 @@ public class PushTextSendJob extends PushSendJob implements InjectableType {
|
|||
database.markAsSent(messageId, true);
|
||||
database.markUnidentified(messageId, unidentified);
|
||||
|
||||
if (TextSecurePreferences.isUnidentifiedDeliveryEnabled(context)) {
|
||||
Recipient recipient = record.getRecipient().resolve();
|
||||
UnidentifiedAccessMode accessMode = recipient.getUnidentifiedAccessMode();
|
||||
|
||||
if (unidentified && (accessMode == UnidentifiedAccessMode.UNKNOWN || accessMode == UnidentifiedAccessMode.DISABLED)) {
|
||||
Log.i(TAG, "Marking recipient as UD-enabled following a UD send.");
|
||||
DatabaseFactory.getRecipientDatabase(context).setUnidentifiedAccessMode(recipient, UnidentifiedAccessMode.ENABLED);
|
||||
} else if (!unidentified && accessMode != UnidentifiedAccessMode.DISABLED) {
|
||||
Log.i(TAG, "Marking recipient as UD-disabled following a non-UD send.");
|
||||
DatabaseFactory.getRecipientDatabase(context).setUnidentifiedAccessMode(recipient, UnidentifiedAccessMode.DISABLED);
|
||||
}
|
||||
}
|
||||
|
||||
if (record.getExpiresIn() > 0) {
|
||||
database.markExpireStarted(messageId);
|
||||
expirationManager.scheduleDeletion(record.getId(), record.isMms(), record.getExpiresIn());
|
||||
|
|
|
@ -3,6 +3,7 @@ package org.thoughtcrime.securesms.jobs;
|
|||
import android.content.Context;
|
||||
import android.support.annotation.NonNull;
|
||||
|
||||
import org.thoughtcrime.securesms.ApplicationContext;
|
||||
import org.thoughtcrime.securesms.jobmanager.SafeData;
|
||||
import org.thoughtcrime.securesms.logging.Log;
|
||||
|
||||
|
@ -10,10 +11,6 @@ import org.thoughtcrime.securesms.dependencies.InjectableType;
|
|||
import org.thoughtcrime.securesms.jobmanager.JobParameters;
|
||||
|
||||
import org.thoughtcrime.securesms.crypto.UnidentifiedAccessUtil;
|
||||
import org.thoughtcrime.securesms.dependencies.InjectableType;
|
||||
import org.thoughtcrime.securesms.jobmanager.JobParameters;
|
||||
import org.thoughtcrime.securesms.jobmanager.requirements.NetworkRequirement;
|
||||
import org.thoughtcrime.securesms.logging.Log;
|
||||
import org.thoughtcrime.securesms.util.TextSecurePreferences;
|
||||
import org.whispersystems.signalservice.api.SignalServiceAccountManager;
|
||||
import org.whispersystems.signalservice.api.push.exceptions.NetworkFailureException;
|
||||
|
@ -63,6 +60,10 @@ public class RefreshAttributesJob extends ContextJob implements InjectableType {
|
|||
|
||||
signalAccountManager.setAccountAttributes(signalingKey, registrationId, fetchesMessages, pin,
|
||||
unidentifiedAccessKey, universalUnidentifiedAccess);
|
||||
|
||||
ApplicationContext.getInstance(context)
|
||||
.getJobManager()
|
||||
.add(new RefreshUnidentifiedDeliveryAbilityJob(context));
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -0,0 +1,96 @@
|
|||
package org.thoughtcrime.securesms.jobs;
|
||||
|
||||
import android.content.Context;
|
||||
import android.support.annotation.NonNull;
|
||||
|
||||
import org.thoughtcrime.securesms.crypto.ProfileKeyUtil;
|
||||
import org.thoughtcrime.securesms.dependencies.InjectableType;
|
||||
import org.thoughtcrime.securesms.jobmanager.JobParameters;
|
||||
import org.thoughtcrime.securesms.jobmanager.SafeData;
|
||||
import org.thoughtcrime.securesms.logging.Log;
|
||||
import org.thoughtcrime.securesms.service.IncomingMessageObserver;
|
||||
import org.thoughtcrime.securesms.util.Base64;
|
||||
import org.thoughtcrime.securesms.util.TextSecurePreferences;
|
||||
import org.whispersystems.libsignal.util.guava.Optional;
|
||||
import org.whispersystems.signalservice.api.SignalServiceMessagePipe;
|
||||
import org.whispersystems.signalservice.api.SignalServiceMessageReceiver;
|
||||
import org.whispersystems.signalservice.api.crypto.ProfileCipher;
|
||||
import org.whispersystems.signalservice.api.profiles.SignalServiceProfile;
|
||||
import org.whispersystems.signalservice.api.push.SignalServiceAddress;
|
||||
import org.whispersystems.signalservice.api.push.exceptions.PushNetworkException;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import javax.inject.Inject;
|
||||
|
||||
import androidx.work.Data;
|
||||
|
||||
public class RefreshUnidentifiedDeliveryAbilityJob extends ContextJob implements InjectableType {
|
||||
|
||||
private static final String TAG = RefreshUnidentifiedDeliveryAbilityJob.class.getSimpleName();
|
||||
|
||||
@Inject transient SignalServiceMessageReceiver receiver;
|
||||
|
||||
public RefreshUnidentifiedDeliveryAbilityJob() {
|
||||
super(null, null);
|
||||
}
|
||||
|
||||
public RefreshUnidentifiedDeliveryAbilityJob(Context context) {
|
||||
super(context, new JobParameters.Builder()
|
||||
.withNetworkRequirement()
|
||||
.create());
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void initialize(@NonNull SafeData data) { }
|
||||
|
||||
@Override
|
||||
protected @NonNull Data serialize(@NonNull Data.Builder dataBuilder) {
|
||||
return dataBuilder.build();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onRun() throws Exception {
|
||||
byte[] profileKey = ProfileKeyUtil.getProfileKey(context);
|
||||
SignalServiceProfile profile = retrieveProfile(TextSecurePreferences.getLocalNumber(context));
|
||||
|
||||
boolean enabled = profile.getUnidentifiedAccess() != null && isValidVerifier(profileKey, profile.getUnidentifiedAccess());
|
||||
|
||||
TextSecurePreferences.setIsUnidentifiedDeliveryEnabled(context, enabled);
|
||||
Log.i(TAG, "Set UD status to: " + enabled);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onCanceled() {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean onShouldRetry(Exception exception) {
|
||||
return exception instanceof PushNetworkException;
|
||||
}
|
||||
|
||||
private SignalServiceProfile retrieveProfile(@NonNull String number) throws IOException {
|
||||
SignalServiceMessagePipe pipe = IncomingMessageObserver.getPipe();
|
||||
|
||||
if (pipe != null) {
|
||||
try {
|
||||
return pipe.getProfile(new SignalServiceAddress(number), Optional.absent());
|
||||
} catch (IOException e) {
|
||||
Log.w(TAG, e);
|
||||
}
|
||||
}
|
||||
|
||||
return receiver.retrieveProfile(new SignalServiceAddress(number), Optional.absent());
|
||||
}
|
||||
|
||||
private boolean isValidVerifier(@NonNull byte[] profileKey, @NonNull String verifier) {
|
||||
ProfileCipher profileCipher = new ProfileCipher(profileKey);
|
||||
try {
|
||||
return profileCipher.verifyUnidentifiedAccess(Base64.decode(verifier));
|
||||
} catch (IOException e) {
|
||||
Log.w(TAG, e);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -30,7 +30,7 @@ import org.whispersystems.signalservice.api.crypto.UnidentifiedAccess;
|
|||
import org.whispersystems.signalservice.api.crypto.UnidentifiedAccessPair;
|
||||
import org.whispersystems.signalservice.api.profiles.SignalServiceProfile;
|
||||
import org.whispersystems.signalservice.api.push.SignalServiceAddress;
|
||||
import org.whispersystems.signalservice.api.push.exceptions.AuthorizationFailedException;
|
||||
import org.whispersystems.signalservice.api.push.exceptions.NonSuccessfulResponseCodeException;
|
||||
import org.whispersystems.signalservice.api.util.InvalidNumberException;
|
||||
|
||||
import java.io.IOException;
|
||||
|
@ -101,9 +101,8 @@ public class RetrieveProfileJob extends ContextJob implements InjectableType {
|
|||
|
||||
try {
|
||||
profile = retrieveProfile(number, unidentifiedAccess);
|
||||
} catch (AuthorizationFailedException e) {
|
||||
} catch (NonSuccessfulResponseCodeException e) {
|
||||
if (unidentifiedAccess.isPresent()) {
|
||||
// XXX Update UI
|
||||
profile = retrieveProfile(number, Optional.absent());
|
||||
} else {
|
||||
throw e;
|
||||
|
@ -129,7 +128,10 @@ public class RetrieveProfileJob extends ContextJob implements InjectableType {
|
|||
private SignalServiceProfile retrieveProfile(@NonNull String number, Optional<UnidentifiedAccess> unidentifiedAccess)
|
||||
throws IOException
|
||||
{
|
||||
SignalServiceMessagePipe pipe = IncomingMessageObserver.getPipe();
|
||||
SignalServiceMessagePipe authPipe = IncomingMessageObserver.getPipe();
|
||||
SignalServiceMessagePipe unidentifiedPipe = IncomingMessageObserver.getUnidentifiedPipe();
|
||||
SignalServiceMessagePipe pipe = unidentifiedPipe != null && unidentifiedAccess.isPresent() ? unidentifiedPipe
|
||||
: authPipe;
|
||||
|
||||
if (pipe != null) {
|
||||
try {
|
||||
|
@ -169,10 +171,11 @@ public class RetrieveProfileJob extends ContextJob implements InjectableType {
|
|||
RecipientDatabase recipientDatabase = DatabaseFactory.getRecipientDatabase(context);
|
||||
byte[] profileKey = recipient.getProfileKey();
|
||||
|
||||
// XXX Update UI
|
||||
if (unrestrictedUnidentifiedAccess) {
|
||||
Log.i(TAG, "Marking recipient UD status as unrestricted.");
|
||||
recipientDatabase.setUnidentifiedAccessMode(recipient, UnidentifiedAccessMode.UNRESTRICTED);
|
||||
} else if (profileKey == null || unidentifiedAccessVerifier == null) {
|
||||
Log.i(TAG, "Marking recipient UD status as disabled.");
|
||||
recipientDatabase.setUnidentifiedAccessMode(recipient, UnidentifiedAccessMode.DISABLED);
|
||||
} else {
|
||||
ProfileCipher profileCipher = new ProfileCipher(profileKey);
|
||||
|
@ -185,7 +188,9 @@ public class RetrieveProfileJob extends ContextJob implements InjectableType {
|
|||
verifiedUnidentifiedAccess = false;
|
||||
}
|
||||
|
||||
recipientDatabase.setUnidentifiedAccessMode(recipient, verifiedUnidentifiedAccess ? UnidentifiedAccessMode.ENABLED : UnidentifiedAccessMode.DISABLED);
|
||||
UnidentifiedAccessMode mode = verifiedUnidentifiedAccess ? UnidentifiedAccessMode.ENABLED : UnidentifiedAccessMode.DISABLED;
|
||||
Log.i(TAG, "Marking recipient UD status as " + mode.name() + " after verification.");
|
||||
recipientDatabase.setUnidentifiedAccessMode(recipient, mode);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
88
src/org/thoughtcrime/securesms/jobs/RotateProfileKeyJob.java
Normal file
88
src/org/thoughtcrime/securesms/jobs/RotateProfileKeyJob.java
Normal file
|
@ -0,0 +1,88 @@
|
|||
package org.thoughtcrime.securesms.jobs;
|
||||
|
||||
import android.content.Context;
|
||||
import android.support.annotation.NonNull;
|
||||
import android.support.annotation.Nullable;
|
||||
|
||||
import org.thoughtcrime.securesms.ApplicationContext;
|
||||
import org.thoughtcrime.securesms.crypto.ProfileKeyUtil;
|
||||
import org.thoughtcrime.securesms.database.Address;
|
||||
import org.thoughtcrime.securesms.dependencies.InjectableType;
|
||||
import org.thoughtcrime.securesms.jobmanager.JobParameters;
|
||||
import org.thoughtcrime.securesms.jobmanager.SafeData;
|
||||
import org.thoughtcrime.securesms.profiles.AvatarHelper;
|
||||
import org.thoughtcrime.securesms.util.TextSecurePreferences;
|
||||
import org.whispersystems.signalservice.api.SignalServiceAccountManager;
|
||||
import org.whispersystems.signalservice.api.push.exceptions.PushNetworkException;
|
||||
import org.whispersystems.signalservice.api.util.StreamDetails;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.IOException;
|
||||
|
||||
import javax.inject.Inject;
|
||||
|
||||
import androidx.work.Data;
|
||||
|
||||
public class RotateProfileKeyJob extends ContextJob implements InjectableType {
|
||||
|
||||
@Inject SignalServiceAccountManager accountManager;
|
||||
|
||||
public RotateProfileKeyJob() {
|
||||
super(null, null);
|
||||
}
|
||||
|
||||
public RotateProfileKeyJob(Context context) {
|
||||
super(context, new JobParameters.Builder()
|
||||
.withGroupId("__ROTATE_PROFILE_KEY__")
|
||||
.withDuplicatesIgnored(true)
|
||||
.withNetworkRequirement()
|
||||
.create());
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
protected Data serialize(@NonNull Data.Builder dataBuilder) {
|
||||
return dataBuilder.build();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void initialize(@NonNull SafeData data) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onRun() throws Exception {
|
||||
byte[] profileKey = ProfileKeyUtil.rotateProfileKey(context);
|
||||
|
||||
accountManager.setProfileName(profileKey, TextSecurePreferences.getProfileName(context));
|
||||
accountManager.setProfileAvatar(profileKey, getProfileAvatar());
|
||||
|
||||
ApplicationContext.getInstance(context)
|
||||
.getJobManager()
|
||||
.add(new RefreshAttributesJob(context));
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onCanceled() {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean onShouldRetry(Exception exception) {
|
||||
return exception instanceof PushNetworkException;
|
||||
}
|
||||
|
||||
private @Nullable StreamDetails getProfileAvatar() {
|
||||
try {
|
||||
Address localAddress = Address.fromSerialized(TextSecurePreferences.getLocalNumber(context));
|
||||
File avatarFile = AvatarHelper.getAvatarFile(context, localAddress);
|
||||
|
||||
if (avatarFile.exists()) {
|
||||
return new StreamDetails(new FileInputStream(avatarFile), "image/jpeg", avatarFile.length());
|
||||
}
|
||||
} catch (IOException e) {
|
||||
return null;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
|
@ -10,6 +10,7 @@ import android.support.annotation.Nullable;
|
|||
import android.support.v7.app.AlertDialog;
|
||||
import android.support.v7.preference.CheckBoxPreference;
|
||||
import android.support.v7.preference.Preference;
|
||||
import android.view.View;
|
||||
import android.widget.Toast;
|
||||
|
||||
import org.thoughtcrime.securesms.ApplicationContext;
|
||||
|
@ -20,9 +21,12 @@ import org.thoughtcrime.securesms.R;
|
|||
import org.thoughtcrime.securesms.components.SwitchPreferenceCompat;
|
||||
import org.thoughtcrime.securesms.crypto.MasterSecretUtil;
|
||||
import org.thoughtcrime.securesms.dependencies.InjectableType;
|
||||
import org.thoughtcrime.securesms.jobs.MultiDeviceConfigurationUpdateJob;
|
||||
import org.thoughtcrime.securesms.jobs.MultiDeviceReadReceiptUpdateJob;
|
||||
import org.thoughtcrime.securesms.jobs.RefreshAttributesJob;
|
||||
import org.thoughtcrime.securesms.lock.RegistrationLockDialog;
|
||||
import org.thoughtcrime.securesms.service.KeyCachingService;
|
||||
import org.thoughtcrime.securesms.util.CommunicationActions;
|
||||
import org.thoughtcrime.securesms.util.TextSecurePreferences;
|
||||
import org.whispersystems.signalservice.api.SignalServiceAccountManager;
|
||||
|
||||
|
@ -34,7 +38,8 @@ import mobi.upod.timedurationpicker.TimeDurationPickerDialog;
|
|||
|
||||
public class AppProtectionPreferenceFragment extends CorrectedPreferenceFragment implements InjectableType {
|
||||
|
||||
private static final String PREFERENCE_CATEGORY_BLOCKED = "preference_category_blocked";
|
||||
private static final String PREFERENCE_CATEGORY_BLOCKED = "preference_category_blocked";
|
||||
private static final String PREFERENCE_UNIDENTIFIED_LEARN_MORE = "pref_unidentified_learn_more";
|
||||
|
||||
private CheckBoxPreference disablePassphrase;
|
||||
|
||||
|
@ -61,6 +66,9 @@ public class AppProtectionPreferenceFragment extends CorrectedPreferenceFragment
|
|||
this.findPreference(TextSecurePreferences.PASSPHRASE_TIMEOUT_INTERVAL_PREF).setOnPreferenceClickListener(new PassphraseIntervalClickListener());
|
||||
this.findPreference(TextSecurePreferences.READ_RECEIPTS_PREF).setOnPreferenceChangeListener(new ReadReceiptToggleListener());
|
||||
this.findPreference(PREFERENCE_CATEGORY_BLOCKED).setOnPreferenceClickListener(new BlockedContactsClickListener());
|
||||
this.findPreference(TextSecurePreferences.SHOW_UNIDENTIFIED_DELIVERY_INDICATORS).setOnPreferenceChangeListener(new ShowUnidentifiedDeliveryIndicatorsChangedListener());
|
||||
this.findPreference(TextSecurePreferences.UNIVERSAL_UNIDENTIFIED_ACCESS).setOnPreferenceChangeListener(new UniversalUnidentifiedAccessChangedListener());
|
||||
this.findPreference(PREFERENCE_UNIDENTIFIED_LEARN_MORE).setOnPreferenceClickListener(new UnidentifiedLearnMoreClickListener());
|
||||
disablePassphrase.setOnPreferenceChangeListener(new DisablePassphraseClickListener());
|
||||
|
||||
initializeVisibility();
|
||||
|
@ -177,7 +185,9 @@ public class AppProtectionPreferenceFragment extends CorrectedPreferenceFragment
|
|||
boolean enabled = (boolean)newValue;
|
||||
ApplicationContext.getInstance(getContext())
|
||||
.getJobManager()
|
||||
.add(new MultiDeviceReadReceiptUpdateJob(getContext(), enabled));
|
||||
.add(new MultiDeviceConfigurationUpdateJob(getContext(),
|
||||
enabled,
|
||||
TextSecurePreferences.isShowUnidentifiedDeliveryIndicatorsEnabled(getContext())));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
@ -271,4 +281,35 @@ public class AppProtectionPreferenceFragment extends CorrectedPreferenceFragment
|
|||
}
|
||||
}
|
||||
|
||||
private class ShowUnidentifiedDeliveryIndicatorsChangedListener implements Preference.OnPreferenceChangeListener {
|
||||
@Override
|
||||
public boolean onPreferenceChange(Preference preference, Object newValue) {
|
||||
boolean enabled = (boolean) newValue;
|
||||
ApplicationContext.getInstance(getContext())
|
||||
.getJobManager()
|
||||
.add(new MultiDeviceConfigurationUpdateJob(getContext(),
|
||||
TextSecurePreferences.isReadReceiptsEnabled(getContext()),
|
||||
enabled));
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
private class UniversalUnidentifiedAccessChangedListener implements Preference.OnPreferenceChangeListener {
|
||||
@Override
|
||||
public boolean onPreferenceChange(Preference preference, Object o) {
|
||||
ApplicationContext.getInstance(getContext())
|
||||
.getJobManager()
|
||||
.add(new RefreshAttributesJob(getContext()));
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
private class UnidentifiedLearnMoreClickListener implements Preference.OnPreferenceClickListener {
|
||||
@Override
|
||||
public boolean onPreferenceClick(Preference preference) {
|
||||
CommunicationActions.openBrowserLink(preference.getContext(), "https://signal.org/blog/secret-sender/");
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -24,12 +24,4 @@ public class SecurityEventListener implements SignalServiceMessageSender.EventLi
|
|||
public void onSecurityEvent(SignalServiceAddress textSecureAddress) {
|
||||
SecurityEvent.broadcastSecurityUpdateEvent(context);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onUnidentifiedAccessFailed(SignalServiceAddress address) {
|
||||
// XXX Update UI
|
||||
DatabaseFactory.getRecipientDatabase(context)
|
||||
.setUnidentifiedAccessMode(Recipient.from(context, Address.fromSerialized(address.getNumber()), false),
|
||||
RecipientDatabase.UnidentifiedAccessMode.DISABLED);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -48,6 +48,7 @@ import org.thoughtcrime.securesms.notifications.NotificationChannels;
|
|||
import org.thoughtcrime.securesms.recipients.RecipientProvider.RecipientDetails;
|
||||
import org.thoughtcrime.securesms.util.FutureTaskListener;
|
||||
import org.thoughtcrime.securesms.util.ListenableFutureTask;
|
||||
import org.thoughtcrime.securesms.util.TextSecurePreferences;
|
||||
import org.thoughtcrime.securesms.util.Util;
|
||||
import org.whispersystems.libsignal.util.guava.Optional;
|
||||
|
||||
|
|
|
@ -41,7 +41,7 @@ public class IncomingMessageObserver implements InjectableType, RequirementListe
|
|||
private static final long REQUEST_TIMEOUT_MINUTES = 1;
|
||||
|
||||
private static SignalServiceMessagePipe pipe = null;
|
||||
public static SignalServiceMessagePipe unidentifiedPipe = null;
|
||||
private static SignalServiceMessagePipe unidentifiedPipe = null;
|
||||
|
||||
private final Context context;
|
||||
private final NetworkRequirement networkRequirement;
|
||||
|
@ -158,7 +158,7 @@ public class IncomingMessageObserver implements InjectableType, RequirementListe
|
|||
Log.i(TAG, "Reading message...");
|
||||
localPipe.read(REQUEST_TIMEOUT_MINUTES, TimeUnit.MINUTES,
|
||||
envelope -> {
|
||||
Log.i(TAG, "Retrieved envelope! " + envelope.getSource());
|
||||
Log.i(TAG, "Retrieved envelope! " + String.valueOf(envelope.getSource()));
|
||||
new PushContentReceiveJob(context).processEnvelope(envelope);
|
||||
});
|
||||
} catch (TimeoutException e) {
|
||||
|
|
|
@ -1,254 +0,0 @@
|
|||
package org.thoughtcrime.securesms.service;
|
||||
|
||||
import android.app.Service;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.os.IBinder;
|
||||
import android.support.annotation.Nullable;
|
||||
import android.support.v4.app.NotificationCompat;
|
||||
|
||||
import org.thoughtcrime.securesms.ApplicationContext;
|
||||
import org.thoughtcrime.securesms.R;
|
||||
import org.thoughtcrime.securesms.dependencies.InjectableType;
|
||||
import org.thoughtcrime.securesms.gcm.GcmBroadcastReceiver;
|
||||
import org.thoughtcrime.securesms.jobmanager.requirements.NetworkRequirement;
|
||||
import org.thoughtcrime.securesms.jobmanager.requirements.NetworkRequirementProvider;
|
||||
import org.thoughtcrime.securesms.jobmanager.requirements.RequirementListener;
|
||||
import org.thoughtcrime.securesms.jobs.PushContentReceiveJob;
|
||||
import org.thoughtcrime.securesms.logging.Log;
|
||||
import org.thoughtcrime.securesms.notifications.NotificationChannels;
|
||||
import org.thoughtcrime.securesms.util.TextSecurePreferences;
|
||||
import org.whispersystems.libsignal.InvalidVersionException;
|
||||
import org.whispersystems.signalservice.api.SignalServiceMessagePipe;
|
||||
import org.whispersystems.signalservice.api.SignalServiceMessageReceiver;
|
||||
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.TimeoutException;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
|
||||
import javax.inject.Inject;
|
||||
|
||||
public class MessageRetrievalService extends Service implements InjectableType, RequirementListener {
|
||||
|
||||
private static final String TAG = MessageRetrievalService.class.getSimpleName();
|
||||
|
||||
public static final String ACTION_ACTIVITY_STARTED = "ACTIVITY_STARTED";
|
||||
public static final String ACTION_ACTIVITY_FINISHED = "ACTIVITY_FINISHED";
|
||||
public static final String ACTION_PUSH_RECEIVED = "PUSH_RECEIVED";
|
||||
public static final String ACTION_INITIALIZE = "INITIALIZE";
|
||||
public static final int FOREGROUND_ID = 313399;
|
||||
|
||||
private static final long REQUEST_TIMEOUT_MINUTES = 1;
|
||||
|
||||
private NetworkRequirement networkRequirement;
|
||||
private NetworkRequirementProvider networkRequirementProvider;
|
||||
|
||||
@Inject
|
||||
public SignalServiceMessageReceiver receiver;
|
||||
|
||||
private int activeActivities = 0;
|
||||
private List<Intent> pushPending = new LinkedList<>();
|
||||
private MessageRetrievalThread retrievalThread = null;
|
||||
|
||||
public static SignalServiceMessagePipe pipe = null;
|
||||
public static SignalServiceMessagePipe unidentifiedPipe = null;
|
||||
|
||||
@Override
|
||||
public void onCreate() {
|
||||
super.onCreate();
|
||||
ApplicationContext.getInstance(this).injectDependencies(this);
|
||||
|
||||
networkRequirement = new NetworkRequirement(this);
|
||||
networkRequirementProvider = new NetworkRequirementProvider(this);
|
||||
|
||||
networkRequirementProvider.setListener(this);
|
||||
|
||||
retrievalThread = new MessageRetrievalThread();
|
||||
retrievalThread.start();
|
||||
|
||||
setForegroundIfNecessary();
|
||||
}
|
||||
|
||||
public int onStartCommand(Intent intent, int flags, int startId) {
|
||||
if (intent == null) return START_STICKY;
|
||||
|
||||
if (ACTION_ACTIVITY_STARTED.equals(intent.getAction())) incrementActive();
|
||||
else if (ACTION_ACTIVITY_FINISHED.equals(intent.getAction())) decrementActive();
|
||||
else if (ACTION_PUSH_RECEIVED.equals(intent.getAction())) incrementPushReceived(intent);
|
||||
|
||||
return START_STICKY;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDestroy() {
|
||||
super.onDestroy();
|
||||
|
||||
if (retrievalThread != null) {
|
||||
retrievalThread.stopThread();
|
||||
}
|
||||
|
||||
sendBroadcast(new Intent("org.thoughtcrime.securesms.RESTART"));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onRequirementStatusChanged() {
|
||||
synchronized (this) {
|
||||
notifyAll();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public IBinder onBind(Intent intent) {
|
||||
return null;
|
||||
}
|
||||
|
||||
private void setForegroundIfNecessary() {
|
||||
if (TextSecurePreferences.isGcmDisabled(this)) {
|
||||
NotificationCompat.Builder builder = new NotificationCompat.Builder(this, NotificationChannels.OTHER);
|
||||
builder.setContentTitle(getString(R.string.MessageRetrievalService_signal));
|
||||
builder.setContentText(getString(R.string.MessageRetrievalService_background_connection_enabled));
|
||||
builder.setPriority(NotificationCompat.PRIORITY_MIN);
|
||||
builder.setWhen(0);
|
||||
builder.setSmallIcon(R.drawable.ic_signal_grey_24dp);
|
||||
startForeground(FOREGROUND_ID, builder.build());
|
||||
}
|
||||
}
|
||||
|
||||
private synchronized void incrementActive() {
|
||||
activeActivities++;
|
||||
Log.d(TAG, "Active Count: " + activeActivities);
|
||||
notifyAll();
|
||||
}
|
||||
|
||||
private synchronized void decrementActive() {
|
||||
activeActivities--;
|
||||
Log.d(TAG, "Active Count: " + activeActivities);
|
||||
notifyAll();
|
||||
}
|
||||
|
||||
private synchronized void incrementPushReceived(Intent intent) {
|
||||
pushPending.add(intent);
|
||||
notifyAll();
|
||||
}
|
||||
|
||||
private synchronized void decrementPushReceived() {
|
||||
if (!pushPending.isEmpty()) {
|
||||
Intent intent = pushPending.remove(0);
|
||||
GcmBroadcastReceiver.completeWakefulIntent(intent);
|
||||
notifyAll();
|
||||
}
|
||||
}
|
||||
|
||||
private synchronized boolean isConnectionNecessary() {
|
||||
boolean isGcmDisabled = TextSecurePreferences.isGcmDisabled(this);
|
||||
|
||||
Log.d(TAG, String.format("Network requirement: %s, active activities: %s, push pending: %s, gcm disabled: %b",
|
||||
networkRequirement.isPresent(), activeActivities, pushPending.size(), isGcmDisabled));
|
||||
|
||||
return TextSecurePreferences.isPushRegistered(this) &&
|
||||
TextSecurePreferences.isWebsocketRegistered(this) &&
|
||||
(activeActivities > 0 || !pushPending.isEmpty() || isGcmDisabled) &&
|
||||
networkRequirement.isPresent();
|
||||
}
|
||||
|
||||
private synchronized void waitForConnectionNecessary() {
|
||||
try {
|
||||
while (!isConnectionNecessary()) wait();
|
||||
} catch (InterruptedException e) {
|
||||
throw new AssertionError(e);
|
||||
}
|
||||
}
|
||||
|
||||
private void shutdown(SignalServiceMessagePipe pipe, SignalServiceMessagePipe unidentifiedPipe) {
|
||||
try {
|
||||
pipe.shutdown();
|
||||
unidentifiedPipe.shutdown();
|
||||
} catch (Throwable t) {
|
||||
Log.w(TAG, t);
|
||||
}
|
||||
}
|
||||
|
||||
public static void registerActivityStarted(Context activity) {
|
||||
Intent intent = new Intent(activity, MessageRetrievalService.class);
|
||||
intent.setAction(MessageRetrievalService.ACTION_ACTIVITY_STARTED);
|
||||
activity.startService(intent);
|
||||
}
|
||||
|
||||
public static void registerActivityStopped(Context activity) {
|
||||
Intent intent = new Intent(activity, MessageRetrievalService.class);
|
||||
intent.setAction(MessageRetrievalService.ACTION_ACTIVITY_FINISHED);
|
||||
activity.startService(intent);
|
||||
}
|
||||
|
||||
public static @Nullable SignalServiceMessagePipe getPipe() {
|
||||
return pipe;
|
||||
}
|
||||
|
||||
public static @Nullable SignalServiceMessagePipe getUnidentifiedPipe() {
|
||||
return unidentifiedPipe;
|
||||
}
|
||||
|
||||
private class MessageRetrievalThread extends Thread implements Thread.UncaughtExceptionHandler {
|
||||
|
||||
private AtomicBoolean stopThread = new AtomicBoolean(false);
|
||||
|
||||
MessageRetrievalThread() {
|
||||
super("MessageRetrievalService");
|
||||
setUncaughtExceptionHandler(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
while (!stopThread.get()) {
|
||||
Log.i(TAG, "Waiting for websocket state change....");
|
||||
waitForConnectionNecessary();
|
||||
|
||||
Log.i(TAG, "Making websocket connection....");
|
||||
pipe = receiver.createMessagePipe();
|
||||
unidentifiedPipe = receiver.createUnidentifiedMessagePipe();
|
||||
|
||||
SignalServiceMessagePipe localPipe = pipe;
|
||||
SignalServiceMessagePipe unidentifiedLocalPipe = unidentifiedPipe;
|
||||
|
||||
try {
|
||||
while (isConnectionNecessary() && !stopThread.get()) {
|
||||
try {
|
||||
Log.i(TAG, "Reading message...");
|
||||
localPipe.read(REQUEST_TIMEOUT_MINUTES, TimeUnit.MINUTES,
|
||||
envelope -> {
|
||||
Log.i(TAG, "Retrieved envelope! " + envelope.getSource());
|
||||
new PushContentReceiveJob(getApplicationContext()).processEnvelope(envelope);
|
||||
decrementPushReceived();
|
||||
});
|
||||
} catch (TimeoutException e) {
|
||||
Log.w(TAG, "Application level read timeout...");
|
||||
} catch (InvalidVersionException e) {
|
||||
Log.w(TAG, e);
|
||||
}
|
||||
}
|
||||
} catch (Throwable e) {
|
||||
Log.w(TAG, e);
|
||||
} finally {
|
||||
Log.w(TAG, "Shutting down pipe...");
|
||||
shutdown(localPipe, unidentifiedLocalPipe);
|
||||
}
|
||||
|
||||
Log.i(TAG, "Looping...");
|
||||
}
|
||||
|
||||
Log.i(TAG, "Exiting...");
|
||||
}
|
||||
|
||||
private void stopThread() {
|
||||
stopThread.set(true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void uncaughtException(Thread t, Throwable e) {
|
||||
Log.w(TAG, "*** Uncaught exception!");
|
||||
Log.w(TAG, e);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -2,6 +2,7 @@ package org.thoughtcrime.securesms.util;
|
|||
|
||||
import android.Manifest;
|
||||
import android.app.Activity;
|
||||
import android.content.ActivityNotFoundException;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.net.Uri;
|
||||
|
@ -10,6 +11,7 @@ import android.support.annotation.NonNull;
|
|||
import android.support.annotation.Nullable;
|
||||
import android.support.v4.app.TaskStackBuilder;
|
||||
import android.text.TextUtils;
|
||||
import android.widget.Toast;
|
||||
|
||||
import org.thoughtcrime.securesms.ConversationActivity;
|
||||
import org.thoughtcrime.securesms.R;
|
||||
|
@ -87,4 +89,13 @@ public class CommunicationActions {
|
|||
}
|
||||
context.startActivity(intent);
|
||||
}
|
||||
|
||||
public static void openBrowserLink(@NonNull Context context, @NonNull String link) {
|
||||
try {
|
||||
Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse(link));
|
||||
context.startActivity(intent);
|
||||
} catch (ActivityNotFoundException e) {
|
||||
Toast.makeText(context, R.string.CommunicationActions_no_browser_found, Toast.LENGTH_SHORT).show();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -164,10 +164,12 @@ public class TextSecurePreferences {
|
|||
private static final String NOTIFICATION_MESSAGES_CHANNEL_VERSION = "pref_notification_messages_channel_version";
|
||||
|
||||
private static final String NEEDS_MESSAGE_PULL = "pref_needs_message_pull";
|
||||
|
||||
|
||||
private static final String UNIDENTIFIED_ACCESS_CERTIFICATE_ROTATION_TIME_PREF = "pref_unidentified_access_certificate_rotation_time";
|
||||
private static final String UNIDENTIFIED_ACCESS_CERTIFICATE = "pref_unidentified_access_certificate";
|
||||
private static final String UNIVERSAL_UNIDENTIFIED_ACCESS = "pref_universal_unidentified_access";
|
||||
public static final String UNIVERSAL_UNIDENTIFIED_ACCESS = "pref_universal_unidentified_access";
|
||||
public static final String SHOW_UNIDENTIFIED_DELIVERY_INDICATORS = "pref_show_unidentifed_delivery_indicators";
|
||||
private static final String UNIDENTIFIED_DELIVERY_ENABLED = "pref_unidentified_delivery_enabled";
|
||||
|
||||
public static boolean isScreenLockEnabled(@NonNull Context context) {
|
||||
return getBooleanPreference(context, SCREEN_LOCK, false);
|
||||
|
@ -540,8 +542,16 @@ public class TextSecurePreferences {
|
|||
return getBooleanPreference(context, UNIVERSAL_UNIDENTIFIED_ACCESS, false);
|
||||
}
|
||||
|
||||
public static void setUniversalUnidentifiedAccess(Context context, boolean value) {
|
||||
setBooleanPreference(context, UNIVERSAL_UNIDENTIFIED_ACCESS, value);
|
||||
public static boolean isShowUnidentifiedDeliveryIndicatorsEnabled(Context context) {
|
||||
return getBooleanPreference(context, SHOW_UNIDENTIFIED_DELIVERY_INDICATORS, false);
|
||||
}
|
||||
|
||||
public static void setIsUnidentifiedDeliveryEnabled(Context context, boolean enabled) {
|
||||
setBooleanPreference(context, UNIDENTIFIED_DELIVERY_ENABLED, enabled);
|
||||
}
|
||||
|
||||
public static boolean isUnidentifiedDeliveryEnabled(Context context) {
|
||||
return getBooleanPreference(context, UNIDENTIFIED_DELIVERY_ENABLED, true);
|
||||
}
|
||||
|
||||
public static long getSignedPreKeyRotationTime(Context context) {
|
||||
|
|
Loading…
Add table
Reference in a new issue