mirror of
https://github.com/signalapp/Signal-Android.git
synced 2026-04-12 13:03:17 +01:00
Compare commits
2 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
4509639915 | ||
|
|
1a6d8ccd8f |
@@ -1,4 +0,0 @@
|
||||
root = true
|
||||
|
||||
[*.kt]
|
||||
indent_size = 2
|
||||
7
.github/workflows/android.yml
vendored
7
.github/workflows/android.yml
vendored
@@ -26,10 +26,3 @@ jobs:
|
||||
|
||||
- name: Build with Gradle
|
||||
run: ./gradlew qa
|
||||
|
||||
- name: Archive reports for failed build
|
||||
if: ${{ failure() }}
|
||||
uses: actions/upload-artifact@v2
|
||||
with:
|
||||
name: reports
|
||||
path: '*/build/reports'
|
||||
|
||||
106
app/build.gradle
106
app/build.gradle
@@ -3,12 +3,9 @@ import org.signal.signing.ApkSignerUtil
|
||||
import java.security.MessageDigest
|
||||
|
||||
apply plugin: 'com.android.application'
|
||||
apply plugin: 'kotlin-android'
|
||||
apply plugin: 'kotlin-kapt'
|
||||
apply plugin: 'com.google.protobuf'
|
||||
apply plugin: 'androidx.navigation.safeargs'
|
||||
apply plugin: 'witness'
|
||||
apply plugin: 'org.jlleitschuh.gradle.ktlint'
|
||||
apply from: 'translations.gradle'
|
||||
apply from: 'witness-verifications.gradle'
|
||||
|
||||
@@ -19,6 +16,12 @@ repositories {
|
||||
includeGroupByRegex "com\\.github\\.chrisbanes.*"
|
||||
}
|
||||
}
|
||||
maven {
|
||||
url "https://raw.github.com/signalapp/maven/master/shortcutbadger/releases/"
|
||||
content {
|
||||
includeGroupByRegex "me\\.leolin.*"
|
||||
}
|
||||
}
|
||||
maven {
|
||||
url "https://raw.github.com/signalapp/maven/master/circular-progress-button/releases/"
|
||||
content {
|
||||
@@ -41,9 +44,6 @@ repositories {
|
||||
mavenCentral()
|
||||
jcenter()
|
||||
mavenLocal()
|
||||
maven {
|
||||
url "https://dl.cloudsmith.io/qxAgwaeEE1vN8aLU/mobilecoin/mobilecoin/maven/"
|
||||
}
|
||||
}
|
||||
|
||||
protobuf {
|
||||
@@ -61,15 +61,15 @@ protobuf {
|
||||
}
|
||||
}
|
||||
|
||||
def canonicalVersionCode = 835
|
||||
def canonicalVersionName = "5.10.2"
|
||||
def canonicalVersionCode = 780
|
||||
def canonicalVersionName = "5.3.7.1"
|
||||
|
||||
def postFixSize = 100
|
||||
def abiPostFix = ['universal' : 0,
|
||||
'armeabi-v7a' : 1,
|
||||
'arm64-v8a' : 2,
|
||||
'x86' : 3,
|
||||
'x86_64' : 4]
|
||||
def abiPostFix = ['universal' : 5,
|
||||
'armeabi-v7a' : 6,
|
||||
'arm64-v8a' : 7,
|
||||
'x86' : 8,
|
||||
'x86_64' : 9]
|
||||
|
||||
def keystores = [ 'debug' : loadKeystoreProperties('keystore.debug.properties') ]
|
||||
|
||||
@@ -80,10 +80,6 @@ android {
|
||||
flavorDimensions 'distribution', 'environment'
|
||||
useLibrary 'org.apache.http.legacy'
|
||||
|
||||
kotlinOptions {
|
||||
freeCompilerArgs = ["-Xallow-result-return-type"]
|
||||
}
|
||||
|
||||
dexOptions {
|
||||
javaMaxHeapSize "4g"
|
||||
}
|
||||
@@ -112,7 +108,6 @@ android {
|
||||
project.ext.set("archivesBaseName", "Signal");
|
||||
|
||||
buildConfigField "long", "BUILD_TIMESTAMP", getLastCommitTimestamp() + "L"
|
||||
buildConfigField "String", "GIT_HASH", "\"${getGitHash()}\""
|
||||
buildConfigField "String", "SIGNAL_URL", "\"https://textsecure-service.whispersystems.org\""
|
||||
buildConfigField "String", "STORAGE_URL", "\"https://storage.signal.org\""
|
||||
buildConfigField "String", "SIGNAL_CDN_URL", "\"https://cdn.signal.org\""
|
||||
@@ -133,8 +128,6 @@ android {
|
||||
buildConfigField "String", "ZKGROUP_SERVER_PUBLIC_PARAMS", "\"AMhf5ywVwITZMsff/eCyudZx9JDmkkkbV6PInzG4p8x3VqVJSFiMvnvlEKWuRob/1eaIetR31IYeAbm0NdOuHH8Qi+Rexi1wLlpzIo1gstHWBfZzy1+qHRV5A4TqPp15YzBPm0WSggW6PbSn+F4lf57VCnHF7p8SvzAA2ZZJPYJURt8X7bbg+H3i+PEjH9DXItNEqs2sNcug37xZQDLm7X0=\""
|
||||
buildConfigField "String[]", "LANGUAGES", "new String[]{\"" + autoResConfig().collect { s -> s.replace('-r', '_') }.join('", "') + '"}'
|
||||
buildConfigField "int", "CANONICAL_VERSION_CODE", "$canonicalVersionCode"
|
||||
buildConfigField "String", "DEFAULT_CURRENCIES", "\"EUR,AUD,GBP,CAD,CNY\""
|
||||
buildConfigField "int[]", "MOBILE_COIN_REGIONS", "new int[]{44}"
|
||||
|
||||
ndk {
|
||||
abiFilters 'armeabi-v7a', 'arm64-v8a', 'x86', 'x86_64'
|
||||
@@ -155,7 +148,6 @@ android {
|
||||
}
|
||||
|
||||
compileOptions {
|
||||
coreLibraryDesugaringEnabled true
|
||||
sourceCompatibility JAVA_VERSION
|
||||
targetCompatibility JAVA_VERSION
|
||||
}
|
||||
@@ -168,8 +160,10 @@ android {
|
||||
exclude 'META-INF/LICENSE'
|
||||
exclude 'META-INF/NOTICE'
|
||||
exclude 'META-INF/proguard/androidx-annotations.pro'
|
||||
exclude '/org/spongycastle/x509/CertPathReviewerMessages.properties'
|
||||
exclude '/org/spongycastle/x509/CertPathReviewerMessages_de.properties'
|
||||
}
|
||||
|
||||
aaptOptions {
|
||||
ignoreAssetsPattern '!contours.tfl:!LMprec_600.emd:!blazeface.tfl'
|
||||
}
|
||||
|
||||
buildTypes {
|
||||
@@ -217,12 +211,6 @@ android {
|
||||
debuggable false
|
||||
matchingFallbacks = ['debug']
|
||||
}
|
||||
mock {
|
||||
initWith debug
|
||||
isDefault false
|
||||
minifyEnabled false
|
||||
matchingFallbacks = ['debug']
|
||||
}
|
||||
}
|
||||
|
||||
productFlavors {
|
||||
@@ -248,21 +236,10 @@ android {
|
||||
buildConfigField "String", "NOPLAY_UPDATE_URL", "$ext.websiteUpdateUrl"
|
||||
}
|
||||
|
||||
study {
|
||||
dimension 'distribution'
|
||||
|
||||
applicationIdSuffix ".study"
|
||||
ext.websiteUpdateUrl = "null"
|
||||
buildConfigField "boolean", "PLAY_STORE_DISABLED", "false"
|
||||
buildConfigField "String", "NOPLAY_UPDATE_URL", "$ext.websiteUpdateUrl"
|
||||
}
|
||||
|
||||
prod {
|
||||
dimension 'environment'
|
||||
|
||||
isDefault true
|
||||
|
||||
buildConfigField "String", "MOBILE_COIN_ENVIRONMENT", "\"mainnet\""
|
||||
}
|
||||
|
||||
staging {
|
||||
@@ -278,12 +255,11 @@ android {
|
||||
buildConfigField "String", "SIGNAL_KEY_BACKUP_URL", "\"https://api-staging.backup.signal.org\""
|
||||
buildConfigField "String", "CDS_MRENCLAVE", "\"c98e00a4e3ff977a56afefe7362a27e4961e4f19e211febfbb19b897e6b80b15\""
|
||||
buildConfigField "KbsEnclave", "KBS_ENCLAVE", "new KbsEnclave(\"823a3b2c037ff0cbe305cc48928cfcc97c9ed4a8ca6d49af6f7d6981fb60a4e9\", " +
|
||||
"\"51a56084c0b21c6b8f62b1bc792ec9bedac4c7c3964bb08ddcab868158c09982\", " +
|
||||
"\"038c40bbbacdc873caa81ac793bb75afde6dfe436a99ab1f15e3f0cbb7434ced\", " +
|
||||
"\"a3baab19ef6ce6f34ab9ebb25ba722725ae44a8872dc0ff08ad6d83a9489de87\")"
|
||||
buildConfigField "KbsEnclave[]", "KBS_FALLBACKS", "new KbsEnclave[0]"
|
||||
buildConfigField "String", "UNIDENTIFIED_SENDER_TRUST_ROOT", "\"BbqY1DzohE4NUZoVF+L18oUPrK3kILllLEJh2UnPSsEx\""
|
||||
buildConfigField "String", "ZKGROUP_SERVER_PUBLIC_PARAMS", "\"ABSY21VckQcbSXVNCGRYJcfWHiAMZmpTtTELcDmxgdFbtp/bWsSxZdMKzfCp8rvIs8ocCU3B37fT3r4Mi5qAemeGeR2X+/YmOGR5ofui7tD5mDQfstAI9i+4WpMtIe8KC3wU5w3Inq3uNWVmoGtpKndsNfwJrCg0Hd9zmObhypUnSkfYn2ooMOOnBpfdanRtrvetZUayDMSC5iSRcXKpdls=\""
|
||||
buildConfigField "String", "MOBILE_COIN_ENVIRONMENT", "\"testnet\""
|
||||
}
|
||||
}
|
||||
|
||||
@@ -299,18 +275,6 @@ android {
|
||||
}
|
||||
}
|
||||
|
||||
android.variantFilter { variant ->
|
||||
def distribution = variant.getFlavors().get(0).name
|
||||
def environment = variant.getFlavors().get(1).name
|
||||
def buildType = variant.buildType.name
|
||||
|
||||
if (distribution == 'study' && buildType != 'perf' && buildType != 'mock') {
|
||||
variant.setIgnore(true)
|
||||
} else if (distribution != 'study' && buildType == 'mock') {
|
||||
variant.setIgnore(true)
|
||||
}
|
||||
}
|
||||
|
||||
lintOptions {
|
||||
abortOnError true
|
||||
baseline file("lint-baseline.xml")
|
||||
@@ -327,8 +291,6 @@ android {
|
||||
dependencies {
|
||||
lintChecks project(':lintchecks')
|
||||
|
||||
coreLibraryDesugaring 'com.android.tools:desugar_jdk_libs:1.1.5'
|
||||
|
||||
implementation ('androidx.appcompat:appcompat:1.2.0') {
|
||||
force = true
|
||||
}
|
||||
@@ -353,7 +315,8 @@ dependencies {
|
||||
implementation "androidx.camera:camera-view:1.0.0-alpha18"
|
||||
implementation "androidx.concurrent:concurrent-futures:1.0.0"
|
||||
implementation "androidx.autofill:autofill:1.0.0"
|
||||
implementation "androidx.biometric:biometric:1.1.0"
|
||||
implementation 'com.google.firebase:firebase-ml-vision:24.0.3'
|
||||
implementation 'com.google.firebase:firebase-ml-vision-face-model:20.0.1'
|
||||
|
||||
implementation ('com.google.firebase:firebase-messaging:20.2.0') {
|
||||
exclude group: 'com.google.firebase', module: 'firebase-core'
|
||||
@@ -375,28 +338,22 @@ dependencies {
|
||||
implementation project(':paging')
|
||||
implementation project(':core-util')
|
||||
implementation project(':video')
|
||||
implementation project(':device-transfer')
|
||||
|
||||
implementation 'org.signal:zkgroup-android:0.7.0'
|
||||
implementation 'org.whispersystems:signal-client-android:0.1.7'
|
||||
implementation 'org.whispersystems:signal-client-android:0.1.5'
|
||||
implementation 'com.google.protobuf:protobuf-javalite:3.10.0'
|
||||
|
||||
implementation('com.mobilecoin:android-sdk:1.0.0') {
|
||||
exclude group: 'com.google.protobuf'
|
||||
}
|
||||
|
||||
implementation 'org.signal:argon2:13.1@aar'
|
||||
|
||||
implementation 'org.signal:ringrtc-android:2.9.6'
|
||||
implementation 'org.signal:ringrtc-android:2.8.10'
|
||||
|
||||
implementation "me.leolin:ShortcutBadger:1.1.22"
|
||||
implementation "me.leolin:ShortcutBadger:1.1.16"
|
||||
implementation 'se.emilsjolander:stickylistheaders:2.7.0'
|
||||
implementation 'com.jpardogo.materialtabstrip:library:1.0.9'
|
||||
implementation 'org.apache.httpcomponents:httpclient-android:4.3.5'
|
||||
implementation 'com.github.chrisbanes:PhotoView:2.1.3'
|
||||
implementation 'com.github.bumptech.glide:glide:4.11.0'
|
||||
kapt 'com.github.bumptech.glide:compiler:4.11.0'
|
||||
kapt 'androidx.annotation:annotation:1.1.0'
|
||||
annotationProcessor 'com.github.bumptech.glide:compiler:4.11.0'
|
||||
annotationProcessor 'androidx.annotation:annotation:1.1.0'
|
||||
implementation 'com.makeramen:roundedimageview:2.1.0'
|
||||
implementation 'com.pnikosis:materialish-progress:1.5'
|
||||
implementation 'org.greenrobot:eventbus:3.0.0'
|
||||
@@ -425,7 +382,7 @@ dependencies {
|
||||
exclude group: 'com.android.support', module: 'recyclerview-v7'
|
||||
}
|
||||
|
||||
implementation 'com.airbnb.android:lottie:3.6.0'
|
||||
implementation 'com.airbnb.android:lottie:3.0.7'
|
||||
|
||||
implementation 'com.codewaves.stickyheadergrid:stickyheadergrid:0.9.4'
|
||||
implementation 'com.github.dmytrodanylyk.circular-progress-button:library:1.1.3-S2'
|
||||
@@ -456,8 +413,6 @@ dependencies {
|
||||
|
||||
androidTestImplementation 'androidx.test.ext:junit:1.1.1'
|
||||
androidTestImplementation 'androidx.test.espresso:espresso-core:3.2.0'
|
||||
|
||||
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
|
||||
}
|
||||
|
||||
dependencyVerification {
|
||||
@@ -537,15 +492,6 @@ def getLastCommitTimestamp() {
|
||||
}
|
||||
}
|
||||
|
||||
def getGitHash() {
|
||||
def stdout = new ByteArrayOutputStream()
|
||||
exec {
|
||||
commandLine 'git', 'rev-parse', '--short', 'HEAD'
|
||||
standardOutput = stdout
|
||||
}
|
||||
return stdout.toString().trim()
|
||||
}
|
||||
|
||||
tasks.withType(Test) {
|
||||
testLogging {
|
||||
events "failed"
|
||||
|
||||
@@ -31,8 +31,6 @@
|
||||
<issue id="LogNotAppSignal" severity="error" />
|
||||
<issue id="LogTagInlined" severity="error" />
|
||||
|
||||
<issue id="AlertDialogBuilderUsage" severity="warning" />
|
||||
|
||||
<issue id="RestrictedApi" severity="error">
|
||||
<ignore path="*/org/thoughtcrime/securesms/mediasend/camerax/VideoCapture.java" />
|
||||
<ignore path="*/org/thoughtcrime/securesms/mediasend/camerax/CameraXModule.java" />
|
||||
|
||||
@@ -17,7 +17,6 @@ import net.sqlcipher.database.SQLiteStatement;
|
||||
|
||||
import org.signal.core.util.logging.Log;
|
||||
import org.thoughtcrime.securesms.database.helpers.SQLCipherOpenHelper;
|
||||
import org.thoughtcrime.securesms.util.Hex;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
import java.util.ArrayList;
|
||||
@@ -238,12 +237,7 @@ public class FlipperSqlCipherAdapter extends DatabaseDriver<FlipperSqlCipherAdap
|
||||
case Cursor.FIELD_TYPE_FLOAT:
|
||||
return cursor.getDouble(column);
|
||||
case Cursor.FIELD_TYPE_BLOB:
|
||||
byte[] blob = cursor.getBlob(column);
|
||||
String bytes = blob != null ? "(blob) " + Hex.toStringCondensed(Arrays.copyOf(blob, Math.min(blob.length, 32))) : null;
|
||||
if (bytes != null && bytes.length() == 32 && blob.length > 32) {
|
||||
bytes += "...";
|
||||
}
|
||||
return bytes;
|
||||
return cursor.getBlob(column);
|
||||
case Cursor.FIELD_TYPE_STRING:
|
||||
default:
|
||||
return cursor.getString(column);
|
||||
|
||||
@@ -64,6 +64,7 @@
|
||||
<uses-permission android:name="android.permission.FOREGROUND_SERVICE"/>
|
||||
|
||||
<uses-permission android:name="android.permission.GET_ACCOUNTS" />
|
||||
<uses-permission android:name="com.google.android.c2dm.permission.RECEIVE" />
|
||||
|
||||
<!-- So we can add a TextSecure 'Account' -->
|
||||
<uses-permission android:name="android.permission.READ_SYNC_SETTINGS" />
|
||||
@@ -254,16 +255,6 @@
|
||||
<data android:scheme="https"
|
||||
android:host="signal.group"/>
|
||||
</intent-filter>
|
||||
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.VIEW" />
|
||||
<category android:name="android.intent.category.DEFAULT" />
|
||||
<category android:name="android.intent.category.BROWSABLE" />
|
||||
<data android:scheme="https"
|
||||
android:host="signal.tube" />
|
||||
<data android:scheme="sgnl"
|
||||
android:host="signal.tube" />
|
||||
</intent-filter>
|
||||
</activity>
|
||||
|
||||
<activity android:name=".conversation.ConversationActivity"
|
||||
@@ -359,8 +350,7 @@
|
||||
android:configChanges="touchscreen|keyboard|keyboardHidden|orientation|screenLayout|screenSize"/>
|
||||
|
||||
<activity android:name=".ApplicationPreferencesActivity"
|
||||
android:configChanges="touchscreen|keyboard|keyboardHidden|orientation|screenLayout|screenSize"
|
||||
android:windowSoftInputMode="adjustResize">
|
||||
android:configChanges="touchscreen|keyboard|keyboardHidden|orientation|screenLayout|screenSize">
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.MAIN" />
|
||||
<category android:name="android.intent.category.NOTIFICATION_PREFERENCES" />
|
||||
@@ -377,16 +367,6 @@
|
||||
android:windowSoftInputMode="stateAlwaysHidden">
|
||||
</activity>
|
||||
|
||||
<activity android:name=".devicetransfer.olddevice.OldDeviceTransferActivity"
|
||||
android:theme="@style/TextSecure.LightRegistrationTheme"
|
||||
android:launchMode="singleTask"
|
||||
android:configChanges="touchscreen|keyboard|keyboardHidden|orientation|screenLayout|screenSize"/>
|
||||
|
||||
<activity android:name=".devicetransfer.olddevice.OldDeviceExitActivity"
|
||||
android:noHistory="true"
|
||||
android:excludeFromRecents="true"
|
||||
android:configChanges="touchscreen|keyboard|keyboardHidden|orientation|screenLayout|screenSize"/>
|
||||
|
||||
<activity android:name=".registration.RegistrationNavigationActivity"
|
||||
android:launchMode="singleTask"
|
||||
android:theme="@style/TextSecure.LightRegistrationTheme"
|
||||
@@ -497,10 +477,6 @@
|
||||
android:theme="@style/TextSecure.LightTheme"
|
||||
android:windowSoftInputMode="stateVisible|adjustResize" />
|
||||
|
||||
<activity android:name=".payments.preferences.PaymentsActivity"
|
||||
android:theme="@style/TextSecure.LightRegistrationTheme"
|
||||
android:configChanges="touchscreen|keyboard|keyboardHidden|orientation|screenLayout|screenSize"/>
|
||||
|
||||
<activity android:name=".lock.v2.CreateKbsPinActivity"
|
||||
android:theme="@style/TextSecure.LightRegistrationTheme"
|
||||
android:windowSoftInputMode="adjustResize"
|
||||
@@ -585,7 +561,7 @@
|
||||
android:screenOrientation="portrait"
|
||||
android:theme="@style/Theme.Signal.WallpaperCropper" />
|
||||
|
||||
<service android:enabled="true" android:name=".service.webrtc.WebRtcCallService"/>
|
||||
<service android:enabled="true" android:name=".service.WebRtcCallService"/>
|
||||
<service android:enabled="true" android:name=".service.ApplicationMigrationService"/>
|
||||
<service android:enabled="true" android:exported="false" android:name=".service.KeyCachingService"/>
|
||||
<service android:enabled="true" android:name=".messages.IncomingMessageObserver$ForegroundService"/>
|
||||
@@ -716,8 +692,6 @@
|
||||
|
||||
<receiver android:name=".service.TrimThreadsByDateManager$TrimThreadsByDateAlarm" />
|
||||
|
||||
<receiver android:name=".payments.backup.phrase.ClearClipboardAlarmReceiver" />
|
||||
|
||||
<provider android:name=".providers.PartProvider"
|
||||
android:grantUriPermissions="true"
|
||||
android:exported="false"
|
||||
@@ -746,6 +720,10 @@
|
||||
android:authorities="${applicationId}.database.conversation"
|
||||
android:exported="false" />
|
||||
|
||||
<provider android:name=".database.DatabaseContentProviders$ConversationList"
|
||||
android:authorities="${applicationId}.database.conversationlist"
|
||||
android:exported="false" />
|
||||
|
||||
<provider android:name=".database.DatabaseContentProviders$Attachment"
|
||||
android:authorities="${applicationId}.database.attachment"
|
||||
android:exported="false" />
|
||||
@@ -783,13 +761,6 @@
|
||||
</intent-filter>
|
||||
</receiver>
|
||||
|
||||
<receiver android:name=".messageprocessingalarm.MessageProcessReceiver">
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.BOOT_COMPLETED" />
|
||||
<action android:name="org.thoughtcrime.securesms.action.PROCESS_MESSAGES" />
|
||||
</intent-filter>
|
||||
</receiver>
|
||||
|
||||
<receiver android:name=".service.LocalBackupListener">
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.BOOT_COMPLETED" />
|
||||
|
||||
@@ -65,8 +65,6 @@ import androidx.lifecycle.LiveData;
|
||||
|
||||
import com.google.common.util.concurrent.ListenableFuture;
|
||||
|
||||
import org.signal.core.util.logging.Log;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.concurrent.Executor;
|
||||
|
||||
@@ -84,7 +82,7 @@ import java.util.concurrent.Executor;
|
||||
@RequiresApi(21)
|
||||
@SuppressLint("RestrictedApi")
|
||||
public final class SignalCameraView extends FrameLayout {
|
||||
static final String TAG = Log.tag(SignalCameraView.class);
|
||||
static final String TAG = SignalCameraView.class.getSimpleName();
|
||||
|
||||
static final int INDEFINITE_VIDEO_DURATION = -1;
|
||||
static final int INDEFINITE_VIDEO_SIZE = -1;
|
||||
|
||||
@@ -24,7 +24,7 @@ public final class Log {
|
||||
}
|
||||
|
||||
public static void e(@NonNull String tag, @NonNull String message) {
|
||||
SignalGlideCodecs.getLogProvider().e(tag, message, null);
|
||||
e(tag, message, null);
|
||||
}
|
||||
|
||||
public static void e(@NonNull String tag, @NonNull String message, @Nullable Throwable throwable) {
|
||||
|
||||
@@ -12,7 +12,7 @@ import android.graphics.Paint;
|
||||
import android.graphics.PorterDuff;
|
||||
import android.graphics.Rect;
|
||||
|
||||
import org.signal.core.util.logging.Log;
|
||||
import org.signal.glide.Log;
|
||||
import org.signal.glide.apng.io.APNGReader;
|
||||
import org.signal.glide.apng.io.APNGWriter;
|
||||
import org.signal.glide.common.decode.Frame;
|
||||
@@ -32,7 +32,7 @@ import java.util.List;
|
||||
*/
|
||||
public class APNGDecoder extends FrameSeqDecoder<APNGReader, APNGWriter> {
|
||||
|
||||
private static final String TAG = Log.tag(APNGDecoder.class);
|
||||
private static final String TAG = APNGDecoder.class.getSimpleName();
|
||||
|
||||
private APNGWriter apngWriter;
|
||||
private int mLoopCount;
|
||||
|
||||
@@ -21,7 +21,7 @@ import android.os.Message;
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.vectordrawable.graphics.drawable.Animatable2Compat;
|
||||
|
||||
import org.signal.core.util.logging.Log;
|
||||
import org.signal.glide.Log;
|
||||
import org.signal.glide.common.decode.FrameSeqDecoder;
|
||||
import org.signal.glide.common.loader.Loader;
|
||||
|
||||
@@ -35,7 +35,7 @@ import java.util.Set;
|
||||
* @CreateDate: 2019/3/27
|
||||
*/
|
||||
public abstract class FrameAnimationDrawable<Decoder extends FrameSeqDecoder> extends Drawable implements Animatable2Compat, FrameSeqDecoder.RenderListener {
|
||||
private static final String TAG = Log.tag(FrameAnimationDrawable.class);
|
||||
private static final String TAG = FrameAnimationDrawable.class.getSimpleName();
|
||||
private final Paint paint = new Paint();
|
||||
private final Decoder frameSeqDecoder;
|
||||
private DrawFilter drawFilter = new PaintFlagsDrawFilter(0, Paint.ANTI_ALIAS_FLAG | Paint.FILTER_BITMAP_FLAG);
|
||||
|
||||
@@ -15,7 +15,7 @@ import android.os.Looper;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.annotation.WorkerThread;
|
||||
|
||||
import org.signal.core.util.logging.Log;
|
||||
import org.signal.glide.Log;
|
||||
import org.signal.glide.common.executor.FrameDecoderExecutor;
|
||||
import org.signal.glide.common.io.Reader;
|
||||
import org.signal.glide.common.io.Writer;
|
||||
@@ -39,7 +39,7 @@ import java.util.concurrent.locks.LockSupport;
|
||||
* @CreateDate: 2019/3/27
|
||||
*/
|
||||
public abstract class FrameSeqDecoder<R extends Reader, W extends Writer> {
|
||||
private static final String TAG = Log.tag(FrameSeqDecoder.class);
|
||||
private static final String TAG = FrameSeqDecoder.class.getSimpleName();
|
||||
private final int taskId;
|
||||
|
||||
private final Loader mLoader;
|
||||
|
||||
@@ -54,7 +54,6 @@ public final class AppInitialization {
|
||||
ApplicationDependencies.getMegaphoneRepository().onFirstEverAppLaunch();
|
||||
SignalStore.onFirstEverAppLaunch();
|
||||
SignalStore.onboarding().clearAll();
|
||||
TextSecurePreferences.onPostBackupRestore(context);
|
||||
ApplicationDependencies.getJobManager().add(StickerPackDownloadJob.forInstall(BlessedPacks.ZOZO.getPackId(), BlessedPacks.ZOZO.getPackKey(), false));
|
||||
ApplicationDependencies.getJobManager().add(StickerPackDownloadJob.forInstall(BlessedPacks.BANDIT.getPackId(), BlessedPacks.BANDIT.getPackKey(), false));
|
||||
ApplicationDependencies.getJobManager().add(StickerPackDownloadJob.forInstall(BlessedPacks.DAY_BY_DAY.getPackId(), BlessedPacks.DAY_BY_DAY.getPackKey(), false));
|
||||
|
||||
@@ -17,18 +17,23 @@
|
||||
package org.thoughtcrime.securesms;
|
||||
|
||||
import android.content.Context;
|
||||
import android.hardware.SensorManager;
|
||||
import android.os.Build;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.annotation.WorkerThread;
|
||||
import androidx.appcompat.app.AppCompatDelegate;
|
||||
import androidx.lifecycle.DefaultLifecycleObserver;
|
||||
import androidx.lifecycle.LifecycleOwner;
|
||||
import androidx.lifecycle.ProcessLifecycleOwner;
|
||||
import androidx.multidex.MultiDexApplication;
|
||||
|
||||
import com.google.android.gms.security.ProviderInstaller;
|
||||
|
||||
import org.conscrypt.Conscrypt;
|
||||
import org.signal.aesgcmprovider.AesGcmProvider;
|
||||
import org.signal.core.util.ShakeDetector;
|
||||
import org.signal.core.util.concurrent.SignalExecutors;
|
||||
import org.signal.core.util.logging.AndroidLogger;
|
||||
import org.signal.core.util.logging.Log;
|
||||
@@ -41,6 +46,7 @@ import org.thoughtcrime.securesms.database.helpers.SQLCipherOpenHelper;
|
||||
import org.thoughtcrime.securesms.dependencies.ApplicationDependencies;
|
||||
import org.thoughtcrime.securesms.dependencies.ApplicationDependencyProvider;
|
||||
import org.thoughtcrime.securesms.gcm.FcmJobService;
|
||||
import org.thoughtcrime.securesms.jobmanager.JobManager;
|
||||
import org.thoughtcrime.securesms.jobs.CreateSignedPreKeyJob;
|
||||
import org.thoughtcrime.securesms.jobs.FcmRefreshJob;
|
||||
import org.thoughtcrime.securesms.jobs.GroupV1MigrationJob;
|
||||
@@ -51,7 +57,6 @@ import org.thoughtcrime.securesms.jobs.RetrieveProfileJob;
|
||||
import org.thoughtcrime.securesms.keyvalue.SignalStore;
|
||||
import org.thoughtcrime.securesms.logging.CustomSignalProtocolLogger;
|
||||
import org.thoughtcrime.securesms.logging.LogSecretProvider;
|
||||
import org.thoughtcrime.securesms.messageprocessingalarm.MessageProcessReceiver;
|
||||
import org.thoughtcrime.securesms.migrations.ApplicationMigrations;
|
||||
import org.thoughtcrime.securesms.notifications.NotificationChannels;
|
||||
import org.thoughtcrime.securesms.providers.BlobProvider;
|
||||
@@ -66,8 +71,8 @@ import org.thoughtcrime.securesms.service.LocalBackupListener;
|
||||
import org.thoughtcrime.securesms.service.RotateSenderCertificateListener;
|
||||
import org.thoughtcrime.securesms.service.RotateSignedPreKeyListener;
|
||||
import org.thoughtcrime.securesms.service.UpdateApkRefreshListener;
|
||||
import org.thoughtcrime.securesms.shakereport.ShakeToReport;
|
||||
import org.thoughtcrime.securesms.storage.StorageSyncHelper;
|
||||
import org.thoughtcrime.securesms.util.AppForegroundObserver;
|
||||
import org.thoughtcrime.securesms.util.AppStartup;
|
||||
import org.thoughtcrime.securesms.util.DynamicTheme;
|
||||
import org.thoughtcrime.securesms.util.FeatureFlags;
|
||||
@@ -81,6 +86,8 @@ import org.webrtc.voiceengine.WebRtcAudioUtils;
|
||||
import org.whispersystems.libsignal.logging.SignalProtocolLoggerProvider;
|
||||
|
||||
import java.security.Security;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
/**
|
||||
@@ -91,11 +98,15 @@ import java.util.concurrent.TimeUnit;
|
||||
*
|
||||
* @author Moxie Marlinspike
|
||||
*/
|
||||
public class ApplicationContext extends MultiDexApplication implements AppForegroundObserver.Listener {
|
||||
public class ApplicationContext extends MultiDexApplication implements DefaultLifecycleObserver {
|
||||
|
||||
private static final String TAG = Log.tag(ApplicationContext.class);
|
||||
private static final String TAG = ApplicationContext.class.getSimpleName();
|
||||
|
||||
private PersistentLogger persistentLogger;
|
||||
private ExpiringMessageManager expiringMessageManager;
|
||||
private ViewOnceMessageManager viewOnceMessageManager;
|
||||
private PersistentLogger persistentLogger;
|
||||
|
||||
private volatile boolean isAppVisible;
|
||||
|
||||
public static ApplicationContext getInstance(Context context) {
|
||||
return (ApplicationContext)context.getApplicationContext();
|
||||
@@ -122,12 +133,11 @@ public class ApplicationContext extends MultiDexApplication implements AppForegr
|
||||
.addBlocking("crash-handling", this::initializeCrashHandling)
|
||||
.addBlocking("eat-db", () -> DatabaseFactory.getInstance(this))
|
||||
.addBlocking("app-dependencies", this::initializeAppDependencies)
|
||||
.addBlocking("notification-channels", () -> NotificationChannels.create(this))
|
||||
.addBlocking("first-launch", this::initializeFirstEverAppLaunch)
|
||||
.addBlocking("app-migrations", this::initializeApplicationMigrations)
|
||||
.addBlocking("ring-rtc", this::initializeRingRtc)
|
||||
.addBlocking("mark-registration", () -> RegistrationUtil.maybeMarkRegistrationComplete(this))
|
||||
.addBlocking("lifecycle-observer", () -> ApplicationDependencies.getAppForegroundObserver().addListener(this))
|
||||
.addBlocking("lifecycle-observer", () -> ProcessLifecycleOwner.get().getLifecycle().addObserver(this))
|
||||
.addBlocking("message-retriever", this::initializeMessageRetrieval)
|
||||
.addBlocking("dynamic-theme", () -> DynamicTheme.setDefaultDayNightMode(this))
|
||||
.addBlocking("vector-compat", () -> {
|
||||
@@ -135,14 +145,6 @@ public class ApplicationContext extends MultiDexApplication implements AppForegr
|
||||
AppCompatDelegate.setCompatVectorFromResourcesEnabled(true);
|
||||
}
|
||||
})
|
||||
.addBlocking("proxy-init", () -> {
|
||||
if (SignalStore.proxy().isProxyEnabled()) {
|
||||
Log.w(TAG, "Proxy detected. Enabling Conscrypt.setUseEngineSocketByDefault()");
|
||||
Conscrypt.setUseEngineSocketByDefault(true);
|
||||
}
|
||||
})
|
||||
.addBlocking("blob-provider", this::initializeBlobProvider)
|
||||
.addBlocking("feature-flags", FeatureFlags::init)
|
||||
.addNonBlocking(this::initializeRevealableMessageManager)
|
||||
.addNonBlocking(this::initializeGcmCheck)
|
||||
.addNonBlocking(this::initializeSignedPreKeyCheck)
|
||||
@@ -151,19 +153,25 @@ public class ApplicationContext extends MultiDexApplication implements AppForegr
|
||||
.addNonBlocking(this::initializePendingMessages)
|
||||
.addNonBlocking(this::initializeCleanup)
|
||||
.addNonBlocking(this::initializeGlideCodecs)
|
||||
.addNonBlocking(FeatureFlags::init)
|
||||
.addNonBlocking(RefreshPreKeysJob::scheduleIfNecessary)
|
||||
.addNonBlocking(StorageSyncHelper::scheduleRoutineSync)
|
||||
.addNonBlocking(() -> ApplicationDependencies.getJobManager().beginJobLoop())
|
||||
.addPostRender(this::initializeExpiringMessageManager)
|
||||
.addPostRender(this::initializeBlobProvider)
|
||||
.addPostRender(() -> NotificationChannels.create(this))
|
||||
.execute();
|
||||
|
||||
ProcessLifecycleOwner.get().getLifecycle().addObserver(this);
|
||||
|
||||
Log.d(TAG, "onCreate() took " + (System.currentTimeMillis() - startTime) + " ms");
|
||||
Tracer.getInstance().end("Application#onCreate()");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onForeground() {
|
||||
public void onStart(@NonNull LifecycleOwner owner) {
|
||||
long startTime = System.currentTimeMillis();
|
||||
isAppVisible = true;
|
||||
Log.i(TAG, "App is now visible.");
|
||||
|
||||
ApplicationDependencies.getFrameRateTracker().begin();
|
||||
@@ -184,7 +192,8 @@ public class ApplicationContext extends MultiDexApplication implements AppForegr
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onBackground() {
|
||||
public void onStop(@NonNull LifecycleOwner owner) {
|
||||
isAppVisible = false;
|
||||
Log.i(TAG, "App is no longer visible.");
|
||||
KeyCachingService.onAppBackgrounded(this);
|
||||
ApplicationDependencies.getMessageNotifier().clearVisibleThread();
|
||||
@@ -192,6 +201,21 @@ public class ApplicationContext extends MultiDexApplication implements AppForegr
|
||||
ApplicationDependencies.getShakeToReport().disable();
|
||||
}
|
||||
|
||||
public ExpiringMessageManager getExpiringMessageManager() {
|
||||
if (expiringMessageManager == null) {
|
||||
initializeExpiringMessageManager();
|
||||
}
|
||||
return expiringMessageManager;
|
||||
}
|
||||
|
||||
public ViewOnceMessageManager getViewOnceMessageManager() {
|
||||
return viewOnceMessageManager;
|
||||
}
|
||||
|
||||
public boolean isAppVisible() {
|
||||
return isAppVisible;
|
||||
}
|
||||
|
||||
public PersistentLogger getPersistentLogger() {
|
||||
return persistentLogger;
|
||||
}
|
||||
@@ -229,7 +253,7 @@ public class ApplicationContext extends MultiDexApplication implements AppForegr
|
||||
|
||||
private void initializeLogging() {
|
||||
persistentLogger = new PersistentLogger(this, LogSecretProvider.getOrCreateAttachmentSecret(this), BuildConfig.VERSION_NAME);
|
||||
org.signal.core.util.logging.Log.initialize(FeatureFlags::internalUser, new AndroidLogger(), persistentLogger);
|
||||
org.signal.core.util.logging.Log.initialize(new AndroidLogger(), persistentLogger);
|
||||
|
||||
SignalProtocolLoggerProvider.setProvider(new CustomSignalProtocolLogger());
|
||||
}
|
||||
@@ -248,7 +272,7 @@ public class ApplicationContext extends MultiDexApplication implements AppForegr
|
||||
}
|
||||
|
||||
private void initializeAppDependencies() {
|
||||
ApplicationDependencies.init(this, new ApplicationDependencyProvider(this));
|
||||
ApplicationDependencies.init(this, new ApplicationDependencyProvider(this, new SignalServiceNetworkAccess(this)));
|
||||
}
|
||||
|
||||
private void initializeFirstEverAppLaunch() {
|
||||
@@ -286,11 +310,11 @@ public class ApplicationContext extends MultiDexApplication implements AppForegr
|
||||
}
|
||||
|
||||
private void initializeExpiringMessageManager() {
|
||||
ApplicationDependencies.getExpiringMessageManager().checkSchedule();
|
||||
this.expiringMessageManager = new ExpiringMessageManager(this);
|
||||
}
|
||||
|
||||
private void initializeRevealableMessageManager() {
|
||||
ApplicationDependencies.getViewOnceMessageManager().scheduleIfNecessary();
|
||||
this.viewOnceMessageManager = new ViewOnceMessageManager(this);
|
||||
}
|
||||
|
||||
private void initializePeriodicTasks() {
|
||||
@@ -298,7 +322,6 @@ public class ApplicationContext extends MultiDexApplication implements AppForegr
|
||||
DirectoryRefreshListener.schedule(this);
|
||||
LocalBackupListener.schedule(this);
|
||||
RotateSenderCertificateListener.schedule(this);
|
||||
MessageProcessReceiver.startOrUpdateAlarm(this);
|
||||
|
||||
if (BuildConfig.PLAY_STORE_DISABLED) {
|
||||
UpdateApkRefreshListener.schedule(this);
|
||||
@@ -307,11 +330,31 @@ public class ApplicationContext extends MultiDexApplication implements AppForegr
|
||||
|
||||
private void initializeRingRtc() {
|
||||
try {
|
||||
if (RtcDeviceLists.hardwareAECBlocked()) {
|
||||
Set<String> HARDWARE_AEC_BLACKLIST = new HashSet<String>() {{
|
||||
add("Pixel");
|
||||
add("Pixel XL");
|
||||
add("Moto G5");
|
||||
add("Moto G (5S) Plus");
|
||||
add("Moto G4");
|
||||
add("TA-1053");
|
||||
add("Mi A1");
|
||||
add("Mi A2");
|
||||
add("E5823"); // Sony z5 compact
|
||||
add("Redmi Note 5");
|
||||
add("FP2"); // Fairphone FP2
|
||||
add("MI 5");
|
||||
}};
|
||||
|
||||
Set<String> OPEN_SL_ES_WHITELIST = new HashSet<String>() {{
|
||||
add("Pixel");
|
||||
add("Pixel XL");
|
||||
}};
|
||||
|
||||
if (HARDWARE_AEC_BLACKLIST.contains(Build.MODEL)) {
|
||||
WebRtcAudioUtils.setWebRtcBasedAcousticEchoCanceler(true);
|
||||
}
|
||||
|
||||
if (!RtcDeviceLists.openSLESAllowed()) {
|
||||
if (!OPEN_SL_ES_WHITELIST.contains(Build.MODEL)) {
|
||||
WebRtcAudioManager.setBlacklistDeviceForOpenSLESUsage(true);
|
||||
}
|
||||
|
||||
@@ -344,7 +387,7 @@ public class ApplicationContext extends MultiDexApplication implements AppForegr
|
||||
if (Build.VERSION.SDK_INT >= 26) {
|
||||
FcmJobService.schedule(this);
|
||||
} else {
|
||||
ApplicationDependencies.getJobManager().add(new PushNotificationReceiveJob());
|
||||
ApplicationDependencies.getJobManager().add(new PushNotificationReceiveJob(this));
|
||||
}
|
||||
TextSecurePreferences.setNeedsMessagePull(this, false);
|
||||
}
|
||||
@@ -352,7 +395,7 @@ public class ApplicationContext extends MultiDexApplication implements AppForegr
|
||||
|
||||
@WorkerThread
|
||||
private void initializeBlobProvider() {
|
||||
BlobProvider.getInstance().initialize(this);
|
||||
BlobProvider.getInstance().onSessionStart(this);
|
||||
}
|
||||
|
||||
@WorkerThread
|
||||
|
||||
@@ -23,7 +23,6 @@ import android.content.SharedPreferences;
|
||||
import android.graphics.PorterDuff;
|
||||
import android.os.Build;
|
||||
import android.os.Bundle;
|
||||
import android.view.View;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
@@ -32,12 +31,8 @@ import androidx.fragment.app.Fragment;
|
||||
import androidx.fragment.app.FragmentManager;
|
||||
import androidx.preference.Preference;
|
||||
|
||||
import org.signal.core.util.logging.Log;
|
||||
import org.thoughtcrime.securesms.conversationlist.model.UnreadPayments;
|
||||
import org.thoughtcrime.securesms.conversationlist.model.UnreadPaymentsLiveData;
|
||||
import org.thoughtcrime.securesms.help.HelpFragment;
|
||||
import org.thoughtcrime.securesms.keyvalue.SignalStore;
|
||||
import org.thoughtcrime.securesms.payments.preferences.PaymentsActivity;
|
||||
import org.thoughtcrime.securesms.preferences.AdvancedPreferenceFragment;
|
||||
import org.thoughtcrime.securesms.preferences.AppProtectionPreferenceFragment;
|
||||
import org.thoughtcrime.securesms.preferences.AppearancePreferenceFragment;
|
||||
@@ -45,12 +40,11 @@ import org.thoughtcrime.securesms.preferences.BackupsPreferenceFragment;
|
||||
import org.thoughtcrime.securesms.preferences.ChatsPreferenceFragment;
|
||||
import org.thoughtcrime.securesms.preferences.CorrectedPreferenceFragment;
|
||||
import org.thoughtcrime.securesms.preferences.DataAndStoragePreferenceFragment;
|
||||
import org.thoughtcrime.securesms.preferences.EditProxyFragment;
|
||||
import org.thoughtcrime.securesms.preferences.NotificationsPreferenceFragment;
|
||||
import org.thoughtcrime.securesms.preferences.SmsMmsPreferenceFragment;
|
||||
import org.thoughtcrime.securesms.preferences.widgets.PaymentsPreference;
|
||||
import org.thoughtcrime.securesms.preferences.widgets.ProfilePreference;
|
||||
import org.thoughtcrime.securesms.preferences.widgets.UsernamePreference;
|
||||
import org.thoughtcrime.securesms.profiles.edit.EditProfileActivity;
|
||||
import org.thoughtcrime.securesms.profiles.manage.ManageProfileActivity;
|
||||
import org.thoughtcrime.securesms.recipients.Recipient;
|
||||
import org.thoughtcrime.securesms.service.KeyCachingService;
|
||||
@@ -71,13 +65,11 @@ import org.thoughtcrime.securesms.util.TextSecurePreferences;
|
||||
public class ApplicationPreferencesActivity extends PassphraseRequiredActivity
|
||||
implements SharedPreferences.OnSharedPreferenceChangeListener
|
||||
{
|
||||
public static final String LAUNCH_TO_BACKUPS_FRAGMENT = "launch.to.backups.fragment";
|
||||
public static final String LAUNCH_TO_HELP_FRAGMENT = "launch.to.help.fragment";
|
||||
public static final String LAUNCH_TO_PROXY_FRAGMENT = "launch.to.proxy.fragment";
|
||||
public static final String LAUNCH_TO_NOTIFICATIONS_FRAGMENT = "launch.to.notifications.fragment";
|
||||
public static final String LAUNCH_TO_BACKUPS_FRAGMENT = "launch.to.backups.fragment";
|
||||
public static final String LAUNCH_TO_HELP_FRAGMENT = "launch.to.help.fragment";
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
private static final String TAG = Log.tag(ApplicationPreferencesActivity.class);
|
||||
private static final String TAG = ApplicationPreferencesActivity.class.getSimpleName();
|
||||
|
||||
private static final String PREFERENCE_CATEGORY_PROFILE = "preference_category_profile";
|
||||
private static final String PREFERENCE_CATEGORY_USERNAME = "preference_category_username";
|
||||
@@ -91,7 +83,6 @@ public class ApplicationPreferencesActivity extends PassphraseRequiredActivity
|
||||
private static final String PREFERENCE_CATEGORY_HELP = "preference_category_help";
|
||||
private static final String PREFERENCE_CATEGORY_ADVANCED = "preference_category_advanced";
|
||||
private static final String PREFERENCE_CATEGORY_DONATE = "preference_category_donate";
|
||||
private static final String PREFERENCE_CATEGORY_PAYMENTS = "preference_category_payments";
|
||||
|
||||
private static final String WAS_CONFIGURATION_UPDATED = "was_configuration_updated";
|
||||
|
||||
@@ -116,14 +107,7 @@ public class ApplicationPreferencesActivity extends PassphraseRequiredActivity
|
||||
} else if (getIntent() != null && getIntent().getBooleanExtra(LAUNCH_TO_BACKUPS_FRAGMENT, false)) {
|
||||
initFragment(android.R.id.content, new BackupsPreferenceFragment());
|
||||
} else if (getIntent() != null && getIntent().getBooleanExtra(LAUNCH_TO_HELP_FRAGMENT, false)) {
|
||||
Bundle bundle = new Bundle();
|
||||
bundle.putInt(HelpFragment.START_CATEGORY_INDEX, getIntent().getIntExtra(HelpFragment.START_CATEGORY_INDEX, 0));
|
||||
|
||||
initFragment(android.R.id.content, new HelpFragment(), null, bundle);
|
||||
} else if (getIntent() != null && getIntent().getBooleanExtra(LAUNCH_TO_PROXY_FRAGMENT, false)) {
|
||||
initFragment(android.R.id.content, EditProxyFragment.newInstance());
|
||||
} else if (getIntent() != null && getIntent().getBooleanExtra(LAUNCH_TO_NOTIFICATIONS_FRAGMENT, false)) {
|
||||
initFragment(android.R.id.content, new NotificationsPreferenceFragment());
|
||||
initFragment(android.R.id.content, new HelpFragment());
|
||||
} else if (icicle == null) {
|
||||
initFragment(android.R.id.content, new ApplicationPreferenceFragment());
|
||||
} else {
|
||||
@@ -199,8 +183,6 @@ public class ApplicationPreferencesActivity extends PassphraseRequiredActivity
|
||||
|
||||
public static class ApplicationPreferenceFragment extends CorrectedPreferenceFragment {
|
||||
|
||||
private final UnreadPaymentsLiveData unreadPaymentsLiveData = new UnreadPaymentsLiveData();
|
||||
|
||||
@Override
|
||||
public void onCreate(Bundle icicle) {
|
||||
super.onCreate(icicle);
|
||||
@@ -230,29 +212,9 @@ public class ApplicationPreferencesActivity extends PassphraseRequiredActivity
|
||||
this.findPreference(PREFERENCE_CATEGORY_DONATE)
|
||||
.setOnPreferenceClickListener(new CategoryClickListener(PREFERENCE_CATEGORY_DONATE));
|
||||
|
||||
Preference paymentsPreference = this.findPreference(PREFERENCE_CATEGORY_PAYMENTS);
|
||||
|
||||
if (SignalStore.paymentsValues().getPaymentsAvailability().showPaymentsMenu()) {
|
||||
paymentsPreference.setVisible(true);
|
||||
paymentsPreference.setOnPreferenceClickListener(new CategoryClickListener(PREFERENCE_CATEGORY_PAYMENTS));
|
||||
} else {
|
||||
paymentsPreference.setVisible(false);
|
||||
}
|
||||
|
||||
tintIcons();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
|
||||
super.onViewCreated(view, savedInstanceState);
|
||||
|
||||
if (SignalStore.paymentsValues().getPaymentsAvailability().showPaymentsMenu()) {
|
||||
PaymentsPreference paymentsPreference = (PaymentsPreference) this.findPreference(PREFERENCE_CATEGORY_PAYMENTS);
|
||||
|
||||
unreadPaymentsLiveData.observe(getViewLifecycleOwner(), unreadPayments -> paymentsPreference.setUnreadCount(unreadPayments.transform(UnreadPayments::getUnreadCount).or(-1)));
|
||||
}
|
||||
}
|
||||
|
||||
private void tintIcons() {
|
||||
if (Build.VERSION.SDK_INT >= 21) return;
|
||||
|
||||
@@ -366,9 +328,6 @@ public class ApplicationPreferencesActivity extends PassphraseRequiredActivity
|
||||
case PREFERENCE_CATEGORY_DONATE:
|
||||
CommunicationActions.openBrowserLink(requireContext(), getString(R.string.donate_url));
|
||||
break;
|
||||
case PREFERENCE_CATEGORY_PAYMENTS:
|
||||
startActivity(new Intent(requireContext(), PaymentsActivity.class));
|
||||
break;
|
||||
default:
|
||||
throw new AssertionError();
|
||||
}
|
||||
|
||||
@@ -8,15 +8,11 @@ import androidx.annotation.Nullable;
|
||||
import androidx.lifecycle.LifecycleOwner;
|
||||
import androidx.lifecycle.Observer;
|
||||
|
||||
import org.thoughtcrime.securesms.components.MaskView;
|
||||
import org.thoughtcrime.securesms.components.voice.VoiceNotePlaybackState;
|
||||
import org.thoughtcrime.securesms.contactshare.Contact;
|
||||
import org.thoughtcrime.securesms.conversation.ConversationItem;
|
||||
import org.thoughtcrime.securesms.conversation.ConversationMessage;
|
||||
import org.thoughtcrime.securesms.database.model.InMemoryMessageRecord;
|
||||
import org.thoughtcrime.securesms.database.model.MessageRecord;
|
||||
import org.thoughtcrime.securesms.database.model.MmsMessageRecord;
|
||||
import org.thoughtcrime.securesms.giph.mp4.GiphyMp4Playable;
|
||||
import org.thoughtcrime.securesms.groups.GroupId;
|
||||
import org.thoughtcrime.securesms.groups.GroupMigrationMembershipChange;
|
||||
import org.thoughtcrime.securesms.linkpreview.LinkPreview;
|
||||
@@ -24,14 +20,13 @@ import org.thoughtcrime.securesms.mms.GlideRequests;
|
||||
import org.thoughtcrime.securesms.recipients.Recipient;
|
||||
import org.thoughtcrime.securesms.recipients.RecipientId;
|
||||
import org.thoughtcrime.securesms.stickers.StickerLocator;
|
||||
import org.thoughtcrime.securesms.video.exo.AttachmentMediaSourceFactory;
|
||||
import org.whispersystems.libsignal.util.guava.Optional;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.Set;
|
||||
|
||||
public interface BindableConversationItem extends Unbindable, GiphyMp4Playable {
|
||||
public interface BindableConversationItem extends Unbindable {
|
||||
void bind(@NonNull LifecycleOwner lifecycleOwner,
|
||||
@NonNull ConversationMessage messageRecord,
|
||||
@NonNull Optional<MessageRecord> previousMessageRecord,
|
||||
@@ -42,10 +37,7 @@ public interface BindableConversationItem extends Unbindable, GiphyMp4Playable {
|
||||
@NonNull Recipient recipients,
|
||||
@Nullable String searchQuery,
|
||||
boolean pulseMention,
|
||||
boolean hasWallpaper,
|
||||
boolean isMessageRequestAccepted,
|
||||
@NonNull AttachmentMediaSourceFactory attachmentMediaSourceFactory,
|
||||
boolean canPlayInline);
|
||||
boolean hasWallpaper);
|
||||
|
||||
ConversationMessage getConversationMessage();
|
||||
|
||||
@@ -74,9 +66,6 @@ public interface BindableConversationItem extends Unbindable, GiphyMp4Playable {
|
||||
void onSafetyNumberLearnMoreClicked(@NonNull Recipient recipient);
|
||||
void onJoinGroupCallClicked();
|
||||
void onInviteFriendsToGroupClicked(@NonNull GroupId.V2 groupId);
|
||||
void onEnableCallNotificationsClicked();
|
||||
void onPlayInlineContent(ConversationMessage conversationMessage);
|
||||
void onInMemoryMessageClicked(@NonNull InMemoryMessageRecord messageRecord);
|
||||
|
||||
/** @return true if handled, false if you want to let the normal url handling continue */
|
||||
boolean onUrlClicked(@NonNull String url);
|
||||
|
||||
@@ -11,8 +11,6 @@ import android.widget.TextView;
|
||||
|
||||
import androidx.appcompat.app.AlertDialog;
|
||||
|
||||
import org.signal.core.util.logging.Log;
|
||||
import org.thoughtcrime.securesms.crypto.DatabaseSessionLock;
|
||||
import org.thoughtcrime.securesms.crypto.storage.TextSecureIdentityKeyStore;
|
||||
import org.thoughtcrime.securesms.database.DatabaseFactory;
|
||||
import org.thoughtcrime.securesms.database.MessageDatabase;
|
||||
@@ -29,16 +27,17 @@ import org.thoughtcrime.securesms.util.Base64;
|
||||
import org.thoughtcrime.securesms.util.VerifySpan;
|
||||
import org.whispersystems.libsignal.SignalProtocolAddress;
|
||||
import org.whispersystems.libsignal.util.guava.Optional;
|
||||
import org.whispersystems.signalservice.api.SignalSessionLock;
|
||||
import org.whispersystems.signalservice.api.messages.SignalServiceEnvelope;
|
||||
import org.whispersystems.signalservice.internal.push.SignalServiceProtos;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import static org.whispersystems.libsignal.SessionCipher.SESSION_LOCK;
|
||||
|
||||
public class ConfirmIdentityDialog extends AlertDialog {
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
private static final String TAG = Log.tag(ConfirmIdentityDialog.class);
|
||||
private static final String TAG = ConfirmIdentityDialog.class.getSimpleName();
|
||||
|
||||
private OnClickListener callback;
|
||||
|
||||
@@ -95,7 +94,7 @@ public class ConfirmIdentityDialog extends AlertDialog {
|
||||
{
|
||||
@Override
|
||||
protected Void doInBackground(Void... params) {
|
||||
try (SignalSessionLock.Lock unused = DatabaseSessionLock.INSTANCE.acquire()) {
|
||||
synchronized (SESSION_LOCK) {
|
||||
SignalProtocolAddress mismatchAddress = new SignalProtocolAddress(Recipient.resolved(recipientId).requireServiceId(), 1);
|
||||
TextSecureIdentityKeyStore identityKeyStore = new TextSecureIdentityKeyStore(getContext());
|
||||
|
||||
@@ -137,6 +136,7 @@ public class ConfirmIdentityDialog extends AlertDialog {
|
||||
|
||||
private void processIncomingMessageRecord(MessageRecord messageRecord) {
|
||||
try {
|
||||
PushDatabase pushDatabase = DatabaseFactory.getPushDatabase(getContext());
|
||||
MessageDatabase smsDatabase = DatabaseFactory.getSmsDatabase(getContext());
|
||||
|
||||
smsDatabase.removeMismatchedIdentity(messageRecord.getId(),
|
||||
@@ -155,7 +155,9 @@ public class ConfirmIdentityDialog extends AlertDialog {
|
||||
0,
|
||||
null);
|
||||
|
||||
ApplicationDependencies.getJobManager().add(new PushDecryptMessageJob(getContext(), envelope, messageRecord.getId()));
|
||||
long pushId = pushDatabase.insert(envelope);
|
||||
|
||||
ApplicationDependencies.getJobManager().add(new PushDecryptMessageJob(getContext(), pushId, messageRecord.getId()));
|
||||
} catch (IOException e) {
|
||||
throw new AssertionError(e);
|
||||
}
|
||||
|
||||
@@ -47,7 +47,7 @@ public abstract class ContactSelectionActivity extends PassphraseRequiredActivit
|
||||
ContactSelectionListFragment.OnContactSelectedListener,
|
||||
ContactSelectionListFragment.ScrollCallback
|
||||
{
|
||||
private static final String TAG = Log.tag(ContactSelectionActivity.class);
|
||||
private static final String TAG = ContactSelectionActivity.class.getSimpleName();
|
||||
|
||||
public static final String EXTRA_LAYOUT_RES_ID = "layout_res_id";
|
||||
|
||||
|
||||
@@ -58,7 +58,6 @@ import com.pnikosis.materialishprogress.ProgressWheel;
|
||||
import org.signal.core.util.logging.Log;
|
||||
import org.thoughtcrime.securesms.components.RecyclerViewFastScroller;
|
||||
import org.thoughtcrime.securesms.components.emoji.WarningTextView;
|
||||
import org.thoughtcrime.securesms.contacts.AbstractContactsCursorLoader;
|
||||
import org.thoughtcrime.securesms.contacts.ContactChip;
|
||||
import org.thoughtcrime.securesms.contacts.ContactSelectionListAdapter;
|
||||
import org.thoughtcrime.securesms.contacts.ContactSelectionListItem;
|
||||
@@ -77,7 +76,6 @@ import org.thoughtcrime.securesms.recipients.RecipientId;
|
||||
import org.thoughtcrime.securesms.util.StickyHeaderDecoration;
|
||||
import org.thoughtcrime.securesms.util.TextSecurePreferences;
|
||||
import org.thoughtcrime.securesms.util.UsernameUtil;
|
||||
import org.thoughtcrime.securesms.util.ViewUtil;
|
||||
import org.thoughtcrime.securesms.util.adapter.FixedViewsAdapter;
|
||||
import org.thoughtcrime.securesms.util.adapter.RecyclerViewConcatenateAdapterStickyHeader;
|
||||
import org.thoughtcrime.securesms.util.concurrent.SimpleTask;
|
||||
@@ -115,23 +113,22 @@ public final class ContactSelectionListFragment extends LoggingFragment
|
||||
public static final String CAN_SELECT_SELF = "can_select_self";
|
||||
public static final String DISPLAY_CHIPS = "display_chips";
|
||||
|
||||
private ConstraintLayout constraintLayout;
|
||||
private TextView emptyText;
|
||||
private OnContactSelectedListener onContactSelectedListener;
|
||||
private SwipeRefreshLayout swipeRefresh;
|
||||
private View showContactsLayout;
|
||||
private Button showContactsButton;
|
||||
private TextView showContactsDescription;
|
||||
private ProgressWheel showContactsProgress;
|
||||
private String cursorFilter;
|
||||
private RecyclerView recyclerView;
|
||||
private RecyclerViewFastScroller fastScroller;
|
||||
private ContactSelectionListAdapter cursorRecyclerViewAdapter;
|
||||
private ChipGroup chipGroup;
|
||||
private HorizontalScrollView chipGroupScrollContainer;
|
||||
private WarningTextView groupLimit;
|
||||
private OnSelectionLimitReachedListener onSelectionLimitReachedListener;
|
||||
private AbstractContactsCursorLoaderFactoryProvider cursorFactoryProvider;
|
||||
private ConstraintLayout constraintLayout;
|
||||
private TextView emptyText;
|
||||
private OnContactSelectedListener onContactSelectedListener;
|
||||
private SwipeRefreshLayout swipeRefresh;
|
||||
private View showContactsLayout;
|
||||
private Button showContactsButton;
|
||||
private TextView showContactsDescription;
|
||||
private ProgressWheel showContactsProgress;
|
||||
private String cursorFilter;
|
||||
private RecyclerView recyclerView;
|
||||
private RecyclerViewFastScroller fastScroller;
|
||||
private ContactSelectionListAdapter cursorRecyclerViewAdapter;
|
||||
private ChipGroup chipGroup;
|
||||
private HorizontalScrollView chipGroupScrollContainer;
|
||||
private WarningTextView groupLimit;
|
||||
private OnSelectionLimitReachedListener onSelectionLimitReachedListener;
|
||||
|
||||
|
||||
@Nullable private FixedViewsAdapter headerAdapter;
|
||||
@@ -153,18 +150,10 @@ public final class ContactSelectionListFragment extends LoggingFragment
|
||||
listCallback = (ListCallback) context;
|
||||
}
|
||||
|
||||
if (getParentFragment() instanceof ScrollCallback) {
|
||||
scrollCallback = (ScrollCallback) getParentFragment();
|
||||
}
|
||||
|
||||
if (context instanceof ScrollCallback) {
|
||||
scrollCallback = (ScrollCallback) context;
|
||||
}
|
||||
|
||||
if (getParentFragment() instanceof OnContactSelectedListener) {
|
||||
onContactSelectedListener = (OnContactSelectedListener) getParentFragment();
|
||||
}
|
||||
|
||||
if (context instanceof OnContactSelectedListener) {
|
||||
onContactSelectedListener = (OnContactSelectedListener) context;
|
||||
}
|
||||
@@ -172,14 +161,6 @@ public final class ContactSelectionListFragment extends LoggingFragment
|
||||
if (context instanceof OnSelectionLimitReachedListener) {
|
||||
onSelectionLimitReachedListener = (OnSelectionLimitReachedListener) context;
|
||||
}
|
||||
|
||||
if (context instanceof AbstractContactsCursorLoaderFactoryProvider) {
|
||||
cursorFactoryProvider = (AbstractContactsCursorLoaderFactoryProvider) context;
|
||||
}
|
||||
|
||||
if (getParentFragment() instanceof AbstractContactsCursorLoaderFactoryProvider) {
|
||||
cursorFactoryProvider = (AbstractContactsCursorLoaderFactoryProvider) context;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -208,7 +189,7 @@ public final class ContactSelectionListFragment extends LoggingFragment
|
||||
|
||||
activity.getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_ALWAYS_HIDDEN);
|
||||
|
||||
if (safeArguments().getBoolean(RECENTS, activity.getIntent().getBooleanExtra(RECENTS, false))) {
|
||||
if (activity.getIntent().getBooleanExtra(RECENTS, false)) {
|
||||
LoaderManager.getInstance(this).initLoader(0, null, ContactSelectionListFragment.this);
|
||||
} else {
|
||||
initializeNoContactsPermission();
|
||||
@@ -242,18 +223,14 @@ public final class ContactSelectionListFragment extends LoggingFragment
|
||||
}
|
||||
});
|
||||
|
||||
Intent intent = requireActivity().getIntent();
|
||||
Bundle arguments = safeArguments();
|
||||
Intent intent = requireActivity().getIntent();
|
||||
|
||||
swipeRefresh.setEnabled(arguments.getBoolean(REFRESHABLE, intent.getBooleanExtra(REFRESHABLE, true)));
|
||||
swipeRefresh.setEnabled(intent.getBooleanExtra(REFRESHABLE, true));
|
||||
|
||||
hideCount = arguments.getBoolean(HIDE_COUNT, intent.getBooleanExtra(HIDE_COUNT, false));
|
||||
selectionLimit = arguments.getParcelable(SELECTION_LIMITS);
|
||||
if (selectionLimit == null) {
|
||||
selectionLimit = intent.getParcelableExtra(SELECTION_LIMITS);
|
||||
}
|
||||
isMulti = selectionLimit != null;
|
||||
canSelectSelf = arguments.getBoolean(CAN_SELECT_SELF, intent.getBooleanExtra(CAN_SELECT_SELF, !isMulti));
|
||||
hideCount = intent.getBooleanExtra(HIDE_COUNT, false);
|
||||
selectionLimit = intent.getParcelableExtra(SELECTION_LIMITS);
|
||||
isMulti = selectionLimit != null;
|
||||
canSelectSelf = intent.getBooleanExtra(CAN_SELECT_SELF, !isMulti);
|
||||
|
||||
if (!isMulti) {
|
||||
selectionLimit = SelectionLimits.NO_LIMITS;
|
||||
@@ -266,10 +243,6 @@ public final class ContactSelectionListFragment extends LoggingFragment
|
||||
return view;
|
||||
}
|
||||
|
||||
private @NonNull Bundle safeArguments() {
|
||||
return getArguments() != null ? getArguments() : new Bundle();
|
||||
}
|
||||
|
||||
private void updateGroupLimit(int chipCount) {
|
||||
int members = currentSelection.size() + chipCount;
|
||||
groupLimit.setText(getResources().getQuantityString(R.plurals.ContactSelectionListFragment_d_members, members, members));
|
||||
@@ -299,10 +272,7 @@ public final class ContactSelectionListFragment extends LoggingFragment
|
||||
}
|
||||
|
||||
private Set<RecipientId> getCurrentSelection() {
|
||||
List<RecipientId> currentSelection = safeArguments().getParcelableArrayList(CURRENT_SELECTION);
|
||||
if (currentSelection == null) {
|
||||
currentSelection = requireActivity().getIntent().getParcelableArrayListExtra(CURRENT_SELECTION);
|
||||
}
|
||||
List<RecipientId> currentSelection = requireActivity().getIntent().getParcelableArrayListExtra(CURRENT_SELECTION);
|
||||
|
||||
return currentSelection == null ? Collections.emptySet()
|
||||
: Collections.unmodifiableSet(Stream.of(currentSelection).collect(Collectors.toSet()));
|
||||
@@ -416,15 +386,10 @@ public final class ContactSelectionListFragment extends LoggingFragment
|
||||
|
||||
@Override
|
||||
public @NonNull Loader<Cursor> onCreateLoader(int id, Bundle args) {
|
||||
FragmentActivity activity = requireActivity();
|
||||
int displayMode = safeArguments().getInt(DISPLAY_MODE, activity.getIntent().getIntExtra(DISPLAY_MODE, DisplayMode.FLAG_ALL));
|
||||
boolean displayRecents = safeArguments().getBoolean(RECENTS, activity.getIntent().getBooleanExtra(RECENTS, false));
|
||||
|
||||
if (cursorFactoryProvider != null) {
|
||||
return cursorFactoryProvider.get().create();
|
||||
} else {
|
||||
return new ContactsCursorLoader.Factory(activity, displayMode, cursorFilter, displayRecents).create();
|
||||
}
|
||||
FragmentActivity activity = requireActivity();
|
||||
return new ContactsCursorLoader(activity,
|
||||
activity.getIntent().getIntExtra(DISPLAY_MODE, DisplayMode.FLAG_ALL),
|
||||
cursorFilter, activity.getIntent().getBooleanExtra(RECENTS, false));
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -690,7 +655,7 @@ public final class ContactSelectionListFragment extends LoggingFragment
|
||||
}
|
||||
|
||||
private void setChipGroupVisibility(int visibility) {
|
||||
if (!safeArguments().getBoolean(DISPLAY_CHIPS, requireActivity().getIntent().getBooleanExtra(DISPLAY_CHIPS, true))) {
|
||||
if (!requireActivity().getIntent().getBooleanExtra(DISPLAY_CHIPS, true)) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -707,7 +672,7 @@ public final class ContactSelectionListFragment extends LoggingFragment
|
||||
}
|
||||
|
||||
private void smoothScrollChipsToEnd() {
|
||||
int x = ViewUtil.isLtr(chipGroupScrollContainer) ? chipGroup.getWidth() : 0;
|
||||
int x = chipGroupScrollContainer.getLayoutDirection() == View.LAYOUT_DIRECTION_LTR ? chipGroup.getWidth() : 0;
|
||||
chipGroupScrollContainer.smoothScrollTo(x, 0);
|
||||
}
|
||||
|
||||
@@ -730,8 +695,4 @@ public final class ContactSelectionListFragment extends LoggingFragment
|
||||
public interface ScrollCallback {
|
||||
void onBeginScroll();
|
||||
}
|
||||
|
||||
public interface AbstractContactsCursorLoaderFactoryProvider {
|
||||
@NonNull AbstractContactsCursorLoader.Factory get();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,7 +18,6 @@ import android.widget.Toast;
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.core.content.ContextCompat;
|
||||
|
||||
import org.signal.core.util.ThreadUtil;
|
||||
import org.signal.core.util.logging.Log;
|
||||
import org.thoughtcrime.securesms.crypto.IdentityKeyUtil;
|
||||
import org.thoughtcrime.securesms.crypto.ProfileKeyUtil;
|
||||
@@ -29,6 +28,7 @@ import org.thoughtcrime.securesms.util.Base64;
|
||||
import org.thoughtcrime.securesms.util.DynamicLanguage;
|
||||
import org.thoughtcrime.securesms.util.DynamicTheme;
|
||||
import org.thoughtcrime.securesms.util.TextSecurePreferences;
|
||||
import org.thoughtcrime.securesms.util.Util;
|
||||
import org.thoughtcrime.securesms.util.task.ProgressDialogAsyncTask;
|
||||
import org.whispersystems.libsignal.IdentityKeyPair;
|
||||
import org.whispersystems.libsignal.InvalidKeyException;
|
||||
@@ -45,7 +45,7 @@ public class DeviceActivity extends PassphraseRequiredActivity
|
||||
implements Button.OnClickListener, ScanListener, DeviceLinkFragment.LinkClickedListener
|
||||
{
|
||||
|
||||
private static final String TAG = Log.tag(DeviceActivity.class);
|
||||
private static final String TAG = DeviceActivity.class.getSimpleName();
|
||||
|
||||
private final DynamicTheme dynamicTheme = new DynamicTheme();
|
||||
private final DynamicLanguage dynamicLanguage = new DynamicLanguage();
|
||||
@@ -123,7 +123,7 @@ public class DeviceActivity extends PassphraseRequiredActivity
|
||||
|
||||
@Override
|
||||
public void onQrDataFound(final String data) {
|
||||
ThreadUtil.runOnMain(() -> {
|
||||
Util.runOnMain(() -> {
|
||||
((Vibrator)getSystemService(Context.VIBRATOR_SERVICE)).vibrate(50);
|
||||
Uri uri = Uri.parse(data);
|
||||
deviceLinkFragment.setLinkClickedListener(uri, DeviceActivity.this);
|
||||
|
||||
@@ -40,7 +40,7 @@ public class DeviceListFragment extends ListFragment
|
||||
ListView.OnItemClickListener, Button.OnClickListener
|
||||
{
|
||||
|
||||
private static final String TAG = Log.tag(DeviceListFragment.class);
|
||||
private static final String TAG = DeviceListFragment.class.getSimpleName();
|
||||
|
||||
private SignalServiceAccountManager accountManager;
|
||||
private Locale locale;
|
||||
|
||||
@@ -6,12 +6,10 @@ import android.view.Window;
|
||||
|
||||
import androidx.appcompat.app.AlertDialog;
|
||||
|
||||
import org.signal.core.util.logging.Log;
|
||||
|
||||
public class DeviceProvisioningActivity extends PassphraseRequiredActivity {
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
private static final String TAG = Log.tag(DeviceProvisioningActivity.class);
|
||||
private static final String TAG = DeviceProvisioningActivity.class.getSimpleName();
|
||||
|
||||
@Override
|
||||
protected void onPreCreate() {
|
||||
|
||||
@@ -7,8 +7,6 @@ import android.graphics.PorterDuff;
|
||||
import android.os.AsyncTask;
|
||||
import android.os.Build;
|
||||
import android.os.Bundle;
|
||||
import android.text.Editable;
|
||||
import android.text.TextWatcher;
|
||||
import android.view.View;
|
||||
import android.view.View.OnClickListener;
|
||||
import android.view.ViewGroup;
|
||||
@@ -42,7 +40,6 @@ import org.thoughtcrime.securesms.util.ViewUtil;
|
||||
import org.thoughtcrime.securesms.util.WindowUtil;
|
||||
import org.thoughtcrime.securesms.util.concurrent.ListenableFuture.Listener;
|
||||
import org.thoughtcrime.securesms.util.task.ProgressDialogAsyncTask;
|
||||
import org.thoughtcrime.securesms.util.text.AfterTextChanged;
|
||||
import org.whispersystems.libsignal.util.guava.Optional;
|
||||
|
||||
import java.util.concurrent.ExecutionException;
|
||||
@@ -108,14 +105,6 @@ public class InviteActivity extends PassphraseRequiredActivity implements Contac
|
||||
contactsFragment = (ContactSelectionListFragment)getSupportFragmentManager().findFragmentById(R.id.contact_selection_list_fragment);
|
||||
|
||||
inviteText.setText(getString(R.string.InviteActivity_lets_switch_to_signal, getString(R.string.install_url)));
|
||||
inviteText.addTextChangedListener(new AfterTextChanged(editable -> {
|
||||
boolean isEnabled = editable.length() > 0;
|
||||
smsButton.setEnabled(isEnabled);
|
||||
shareButton.setEnabled(isEnabled);
|
||||
smsButton.animate().alpha(isEnabled ? 1f : 0.5f);
|
||||
shareButton.animate().alpha(isEnabled ? 1f : 0.5f);
|
||||
}));
|
||||
|
||||
updateSmsButtonText(contactsFragment.getSelectedContacts().size());
|
||||
|
||||
smsCancelButton.setOnClickListener(new SmsCancelClickListener());
|
||||
|
||||
@@ -2,7 +2,6 @@ package org.thoughtcrime.securesms;
|
||||
|
||||
import android.os.Bundle;
|
||||
|
||||
import androidx.annotation.LayoutRes;
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.fragment.app.Fragment;
|
||||
@@ -16,12 +15,6 @@ public abstract class LoggingFragment extends Fragment {
|
||||
|
||||
private static final String TAG = Log.tag(LoggingFragment.class);
|
||||
|
||||
public LoggingFragment() { }
|
||||
|
||||
public LoggingFragment(@LayoutRes int contentLayoutId) {
|
||||
super(contentLayoutId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCreate(@Nullable Bundle savedInstanceState) {
|
||||
logEvent("onCreate()");
|
||||
|
||||
@@ -9,8 +9,6 @@ import android.os.Bundle;
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
|
||||
import org.thoughtcrime.securesms.devicetransfer.olddevice.OldDeviceTransferLockedDialog;
|
||||
import org.thoughtcrime.securesms.keyvalue.SignalStore;
|
||||
import org.thoughtcrime.securesms.util.AppStartup;
|
||||
import org.thoughtcrime.securesms.util.CachedInflater;
|
||||
import org.thoughtcrime.securesms.util.CommunicationActions;
|
||||
@@ -43,7 +41,6 @@ public class MainActivity extends PassphraseRequiredActivity {
|
||||
navigator.onCreate(savedInstanceState);
|
||||
|
||||
handleGroupLinkInIntent(getIntent());
|
||||
handleProxyInIntent(getIntent());
|
||||
|
||||
CachedInflater.from(this).clear();
|
||||
}
|
||||
@@ -59,7 +56,6 @@ public class MainActivity extends PassphraseRequiredActivity {
|
||||
protected void onNewIntent(Intent intent) {
|
||||
super.onNewIntent(intent);
|
||||
handleGroupLinkInIntent(intent);
|
||||
handleProxyInIntent(intent);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -72,9 +68,6 @@ public class MainActivity extends PassphraseRequiredActivity {
|
||||
protected void onResume() {
|
||||
super.onResume();
|
||||
dynamicTheme.onResume(this);
|
||||
if (SignalStore.misc().isOldDeviceTransferLocked()) {
|
||||
OldDeviceTransferLockedDialog.show(getSupportFragmentManager());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -102,11 +95,4 @@ public class MainActivity extends PassphraseRequiredActivity {
|
||||
CommunicationActions.handlePotentialGroupLinkUrl(this, data.toString());
|
||||
}
|
||||
}
|
||||
|
||||
private void handleProxyInIntent(Intent intent) {
|
||||
Uri data = intent.getData();
|
||||
if (data != null) {
|
||||
CommunicationActions.handlePotentialProxyLinkUrl(this, data.toString());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -91,7 +91,7 @@ public final class MediaPreviewActivity extends PassphraseRequiredActivity
|
||||
MediaPreviewFragment.Events
|
||||
{
|
||||
|
||||
private final static String TAG = Log.tag(MediaPreviewActivity.class);
|
||||
private final static String TAG = MediaPreviewActivity.class.getSimpleName();
|
||||
|
||||
private static final int NOT_IN_A_THREAD = -2;
|
||||
|
||||
|
||||
@@ -38,10 +38,10 @@ public class MuteDialog extends AlertDialog {
|
||||
|
||||
switch (which) {
|
||||
case 0: muteUntil = System.currentTimeMillis() + TimeUnit.HOURS.toMillis(1); break;
|
||||
case 1: muteUntil = System.currentTimeMillis() + TimeUnit.HOURS.toMillis(8); break;
|
||||
case 1: muteUntil = System.currentTimeMillis() + TimeUnit.HOURS.toMillis(2); break;
|
||||
case 2: muteUntil = System.currentTimeMillis() + TimeUnit.DAYS.toMillis(1); break;
|
||||
case 3: muteUntil = System.currentTimeMillis() + TimeUnit.DAYS.toMillis(7); break;
|
||||
case 4: muteUntil = Long.MAX_VALUE; break;
|
||||
case 4: muteUntil = System.currentTimeMillis() + TimeUnit.DAYS.toMillis(365); break;
|
||||
default: muteUntil = System.currentTimeMillis() + TimeUnit.HOURS.toMillis(1); break;
|
||||
}
|
||||
|
||||
|
||||
@@ -49,7 +49,7 @@ public class NewConversationActivity extends ContactSelectionActivity
|
||||
{
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
private static final String TAG = Log.tag(NewConversationActivity.class);
|
||||
private static final String TAG = NewConversationActivity.class.getSimpleName();
|
||||
|
||||
@Override
|
||||
public void onCreate(Bundle bundle, boolean ready) {
|
||||
|
||||
@@ -34,7 +34,7 @@ import org.thoughtcrime.securesms.service.KeyCachingService;
|
||||
*/
|
||||
public abstract class PassphraseActivity extends BaseActivity {
|
||||
|
||||
private static final String TAG = Log.tag(PassphraseActivity.class);
|
||||
private static final String TAG = PassphraseActivity.class.getSimpleName();
|
||||
|
||||
private KeyCachingService keyCachingService;
|
||||
private MasterSecret masterSecret;
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
package org.thoughtcrime.securesms;
|
||||
|
||||
import android.animation.Animator;
|
||||
import android.annotation.SuppressLint;
|
||||
import android.app.KeyguardManager;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
@@ -45,11 +46,9 @@ import android.widget.ImageButton;
|
||||
import android.widget.ImageView;
|
||||
import android.widget.TextView;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.appcompat.widget.Toolbar;
|
||||
import androidx.biometric.BiometricManager;
|
||||
import androidx.biometric.BiometricManager.Authenticators;
|
||||
import androidx.biometric.BiometricPrompt;
|
||||
import androidx.core.hardware.fingerprint.FingerprintManagerCompat;
|
||||
import androidx.core.os.CancellationSignal;
|
||||
|
||||
import org.signal.core.util.logging.Log;
|
||||
import org.thoughtcrime.securesms.animation.AnimationCompleteListener;
|
||||
@@ -58,10 +57,8 @@ import org.thoughtcrime.securesms.crypto.InvalidPassphraseException;
|
||||
import org.thoughtcrime.securesms.crypto.MasterSecret;
|
||||
import org.thoughtcrime.securesms.crypto.MasterSecretUtil;
|
||||
import org.thoughtcrime.securesms.logsubmit.SubmitDebugLogActivity;
|
||||
import org.thoughtcrime.securesms.util.CommunicationActions;
|
||||
import org.thoughtcrime.securesms.util.DynamicIntroTheme;
|
||||
import org.thoughtcrime.securesms.util.DynamicLanguage;
|
||||
import org.thoughtcrime.securesms.util.SupportEmailUtil;
|
||||
import org.thoughtcrime.securesms.util.TextSecurePreferences;
|
||||
|
||||
/**
|
||||
@@ -71,12 +68,7 @@ import org.thoughtcrime.securesms.util.TextSecurePreferences;
|
||||
*/
|
||||
public class PassphrasePromptActivity extends PassphraseActivity {
|
||||
|
||||
private static final String TAG = Log.tag(PassphrasePromptActivity.class);
|
||||
private static final int BIOMETRIC_AUTHENTICATORS = Authenticators.BIOMETRIC_STRONG | Authenticators.BIOMETRIC_WEAK;
|
||||
private static final int ALLOWED_AUTHENTICATORS = BIOMETRIC_AUTHENTICATORS | Authenticators.DEVICE_CREDENTIAL;
|
||||
private static final short AUTHENTICATE_REQUEST_CODE = 1007;
|
||||
private static final String BUNDLE_ALREADY_SHOWN = "bundle_already_shown";
|
||||
public static final String FROM_FOREGROUND = "from_foreground";
|
||||
private static final String TAG = PassphrasePromptActivity.class.getSimpleName();
|
||||
|
||||
private DynamicIntroTheme dynamicTheme = new DynamicIntroTheme();
|
||||
private DynamicLanguage dynamicLanguage = new DynamicLanguage();
|
||||
@@ -90,13 +82,12 @@ public class PassphrasePromptActivity extends PassphraseActivity {
|
||||
private ImageButton hideButton;
|
||||
private AnimatingToggle visibilityToggle;
|
||||
|
||||
private BiometricManager biometricManager;
|
||||
private BiometricPrompt biometricPrompt;
|
||||
private BiometricPrompt.PromptInfo biometricPromptInfo;
|
||||
private FingerprintManagerCompat fingerprintManager;
|
||||
private CancellationSignal fingerprintCancellationSignal;
|
||||
private FingerprintListener fingerprintListener;
|
||||
|
||||
private boolean authenticated;
|
||||
private boolean hadFailure;
|
||||
private boolean alreadyShown;
|
||||
private boolean failure;
|
||||
|
||||
@Override
|
||||
public void onCreate(Bundle savedInstanceState) {
|
||||
@@ -109,15 +100,6 @@ public class PassphrasePromptActivity extends PassphraseActivity {
|
||||
|
||||
setContentView(R.layout.prompt_passphrase_activity);
|
||||
initializeResources();
|
||||
|
||||
alreadyShown = (savedInstanceState != null && savedInstanceState.getBoolean(BUNDLE_ALREADY_SHOWN)) ||
|
||||
getIntent().getBooleanExtra(FROM_FOREGROUND, false);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onSaveInstanceState(@NonNull Bundle outState) {
|
||||
super.onSaveInstanceState(outState);
|
||||
outState.putBoolean(BUNDLE_ALREADY_SHOWN, alreadyShown);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -128,12 +110,20 @@ public class PassphrasePromptActivity extends PassphraseActivity {
|
||||
|
||||
setLockTypeVisibility();
|
||||
|
||||
if (TextSecurePreferences.isScreenLockEnabled(this) && !authenticated && !hadFailure) {
|
||||
resumeScreenLock(!alreadyShown);
|
||||
alreadyShown = true;
|
||||
if (TextSecurePreferences.isScreenLockEnabled(this) && !authenticated && !failure) {
|
||||
resumeScreenLock();
|
||||
}
|
||||
|
||||
hadFailure = false;
|
||||
failure = false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPause() {
|
||||
super.onPause();
|
||||
|
||||
if (TextSecurePreferences.isScreenLockEnabled(this)) {
|
||||
pauseScreenLock();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -147,7 +137,7 @@ public class PassphrasePromptActivity extends PassphraseActivity {
|
||||
MenuInflater inflater = this.getMenuInflater();
|
||||
menu.clear();
|
||||
|
||||
inflater.inflate(R.menu.passphrase_prompt, menu);
|
||||
inflater.inflate(R.menu.log_submit, menu);
|
||||
|
||||
super.onCreateOptionsMenu(menu);
|
||||
return true;
|
||||
@@ -156,28 +146,23 @@ public class PassphrasePromptActivity extends PassphraseActivity {
|
||||
@Override
|
||||
public boolean onOptionsItemSelected(MenuItem item) {
|
||||
super.onOptionsItemSelected(item);
|
||||
if (item.getItemId() == R.id.menu_submit_debug_logs) {
|
||||
handleLogSubmit();
|
||||
return true;
|
||||
} else if (item.getItemId() == R.id.menu_contact_support) {
|
||||
sendEmailToSupport();
|
||||
return true;
|
||||
switch (item.getItemId()) {
|
||||
case R.id.menu_submit_debug_logs: handleLogSubmit(); return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onActivityResult(int requestCode, int resultCode, Intent data) {
|
||||
super.onActivityResult(requestCode, resultCode, data);
|
||||
@SuppressLint("MissingSuperCall") // no fragments to dispatch to
|
||||
public void onActivityResult(int requestCode, int resultcode, Intent data) {
|
||||
if (requestCode != 1) return;
|
||||
|
||||
if (requestCode != AUTHENTICATE_REQUEST_CODE) return;
|
||||
|
||||
if (resultCode == RESULT_OK) {
|
||||
if (resultcode == RESULT_OK) {
|
||||
handleAuthenticated();
|
||||
} else {
|
||||
Log.w(TAG, "Authentication failed");
|
||||
hadFailure = true;
|
||||
failure = true;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -228,20 +213,16 @@ public class PassphrasePromptActivity extends PassphraseActivity {
|
||||
ImageButton okButton = findViewById(R.id.ok_button);
|
||||
Toolbar toolbar = findViewById(R.id.toolbar);
|
||||
|
||||
showButton = findViewById(R.id.passphrase_visibility);
|
||||
hideButton = findViewById(R.id.passphrase_visibility_off);
|
||||
visibilityToggle = findViewById(R.id.button_toggle);
|
||||
passphraseText = findViewById(R.id.passphrase_edit);
|
||||
passphraseAuthContainer = findViewById(R.id.password_auth_container);
|
||||
fingerprintPrompt = findViewById(R.id.fingerprint_auth_container);
|
||||
lockScreenButton = findViewById(R.id.lock_screen_auth_container);
|
||||
biometricManager = BiometricManager.from(this);
|
||||
biometricPrompt = new BiometricPrompt(this, new BiometricAuthenticationListener());
|
||||
biometricPromptInfo = new BiometricPrompt.PromptInfo
|
||||
.Builder()
|
||||
.setAllowedAuthenticators(ALLOWED_AUTHENTICATORS)
|
||||
.setTitle(getString(R.string.PassphrasePromptActivity_unlock_signal))
|
||||
.build();
|
||||
showButton = findViewById(R.id.passphrase_visibility);
|
||||
hideButton = findViewById(R.id.passphrase_visibility_off);
|
||||
visibilityToggle = findViewById(R.id.button_toggle);
|
||||
passphraseText = findViewById(R.id.passphrase_edit);
|
||||
passphraseAuthContainer = findViewById(R.id.password_auth_container);
|
||||
fingerprintPrompt = findViewById(R.id.fingerprint_auth_container);
|
||||
lockScreenButton = findViewById(R.id.lock_screen_auth_container);
|
||||
fingerprintManager = FingerprintManagerCompat.from(this);
|
||||
fingerprintCancellationSignal = new CancellationSignal();
|
||||
fingerprintListener = new FingerprintListener();
|
||||
|
||||
setSupportActionBar(toolbar);
|
||||
getSupportActionBar().setTitle("");
|
||||
@@ -261,15 +242,20 @@ public class PassphrasePromptActivity extends PassphraseActivity {
|
||||
fingerprintPrompt.setImageResource(R.drawable.ic_fingerprint_white_48dp);
|
||||
fingerprintPrompt.getBackground().setColorFilter(getResources().getColor(R.color.core_ultramarine), PorterDuff.Mode.SRC_IN);
|
||||
|
||||
lockScreenButton.setOnClickListener(v -> resumeScreenLock(true));
|
||||
lockScreenButton.setOnClickListener(v -> resumeScreenLock());
|
||||
}
|
||||
|
||||
private void setLockTypeVisibility() {
|
||||
if (TextSecurePreferences.isScreenLockEnabled(this)) {
|
||||
passphraseAuthContainer.setVisibility(View.GONE);
|
||||
fingerprintPrompt.setVisibility(biometricManager.canAuthenticate(BIOMETRIC_AUTHENTICATORS) == BiometricManager.BIOMETRIC_SUCCESS ? View.VISIBLE
|
||||
: View.GONE);
|
||||
lockScreenButton.setVisibility(View.VISIBLE);
|
||||
|
||||
if (fingerprintManager.isHardwareDetected() && fingerprintManager.hasEnrolledFingerprints()) {
|
||||
fingerprintPrompt.setVisibility(View.VISIBLE);
|
||||
lockScreenButton.setVisibility(View.GONE);
|
||||
} else {
|
||||
fingerprintPrompt.setVisibility(View.GONE);
|
||||
lockScreenButton.setVisibility(View.VISIBLE);
|
||||
}
|
||||
} else {
|
||||
passphraseAuthContainer.setVisibility(View.VISIBLE);
|
||||
fingerprintPrompt.setVisibility(View.GONE);
|
||||
@@ -277,7 +263,7 @@ public class PassphrasePromptActivity extends PassphraseActivity {
|
||||
}
|
||||
}
|
||||
|
||||
private void resumeScreenLock(boolean force) {
|
||||
private void resumeScreenLock() {
|
||||
KeyguardManager keyguardManager = (KeyguardManager) getSystemService(Context.KEYGUARD_SERVICE);
|
||||
|
||||
assert keyguardManager != null;
|
||||
@@ -288,36 +274,24 @@ public class PassphrasePromptActivity extends PassphraseActivity {
|
||||
return;
|
||||
}
|
||||
|
||||
if (Build.VERSION.SDK_INT != 29 && biometricManager.canAuthenticate(ALLOWED_AUTHENTICATORS) == BiometricManager.BIOMETRIC_SUCCESS) {
|
||||
if (force) {
|
||||
Log.i(TAG, "Listening for biometric authentication...");
|
||||
biometricPrompt.authenticate(biometricPromptInfo);
|
||||
} else {
|
||||
Log.i(TAG, "Skipping show system biometric dialog unless forced");
|
||||
}
|
||||
} else if (Build.VERSION.SDK_INT >= 21) {
|
||||
if (force) {
|
||||
Log.i(TAG, "firing intent...");
|
||||
Intent intent = keyguardManager.createConfirmDeviceCredentialIntent(getString(R.string.PassphrasePromptActivity_unlock_signal), "");
|
||||
startActivityForResult(intent, AUTHENTICATE_REQUEST_CODE);
|
||||
} else {
|
||||
Log.i(TAG, "Skipping firing intent unless forced");
|
||||
}
|
||||
if (fingerprintManager.isHardwareDetected() && fingerprintManager.hasEnrolledFingerprints()) {
|
||||
Log.i(TAG, "Listening for fingerprints...");
|
||||
fingerprintCancellationSignal = new CancellationSignal();
|
||||
fingerprintManager.authenticate(null, 0, fingerprintCancellationSignal, fingerprintListener, null);
|
||||
} else if (Build.VERSION.SDK_INT >= 21){
|
||||
Log.i(TAG, "firing intent...");
|
||||
Intent intent = keyguardManager.createConfirmDeviceCredentialIntent(getString(R.string.PassphrasePromptActivity_unlock_signal), "");
|
||||
startActivityForResult(intent, 1);
|
||||
} else {
|
||||
Log.w(TAG, "Not compatible...");
|
||||
handleAuthenticated();
|
||||
}
|
||||
}
|
||||
|
||||
private void sendEmailToSupport() {
|
||||
String body = SupportEmailUtil.generateSupportEmailBody(this,
|
||||
R.string.PassphrasePromptActivity_signal_android_lock_screen,
|
||||
null,
|
||||
null);
|
||||
CommunicationActions.openEmail(this,
|
||||
SupportEmailUtil.getSupportEmailAddress(this),
|
||||
getString(R.string.PassphrasePromptActivity_signal_android_lock_screen),
|
||||
body);
|
||||
private void pauseScreenLock() {
|
||||
if (fingerprintCancellationSignal != null) {
|
||||
fingerprintCancellationSignal.cancel();
|
||||
}
|
||||
}
|
||||
|
||||
private class PassphraseActionListener implements TextView.OnEditorActionListener {
|
||||
@@ -368,19 +342,15 @@ public class PassphrasePromptActivity extends PassphraseActivity {
|
||||
System.gc();
|
||||
}
|
||||
|
||||
private class BiometricAuthenticationListener extends BiometricPrompt.AuthenticationCallback {
|
||||
private class FingerprintListener extends FingerprintManagerCompat.AuthenticationCallback {
|
||||
@Override
|
||||
public void onAuthenticationError(int errorCode, @NonNull CharSequence errorString) {
|
||||
Log.w(TAG, "Authentication error: " + errorCode);
|
||||
hadFailure = true;
|
||||
|
||||
if (errorCode != BiometricPrompt.ERROR_CANCELED && errorCode != BiometricPrompt.ERROR_USER_CANCELED) {
|
||||
onAuthenticationFailed();
|
||||
}
|
||||
public void onAuthenticationError(int errMsgId, CharSequence errString) {
|
||||
Log.w(TAG, "Authentication error: " + errMsgId + " " + errString);
|
||||
onAuthenticationFailed();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onAuthenticationSucceeded(@NonNull BiometricPrompt.AuthenticationResult result) {
|
||||
public void onAuthenticationSucceeded(FingerprintManagerCompat.AuthenticationResult result) {
|
||||
Log.i(TAG, "onAuthenticationSucceeded");
|
||||
fingerprintPrompt.setImageResource(R.drawable.ic_check_white_48dp);
|
||||
fingerprintPrompt.getBackground().setColorFilter(getResources().getColor(R.color.green_500), PorterDuff.Mode.SRC_IN);
|
||||
@@ -397,7 +367,8 @@ public class PassphrasePromptActivity extends PassphraseActivity {
|
||||
|
||||
@Override
|
||||
public void onAuthenticationFailed() {
|
||||
Log.w(TAG, "onAuthenticationFailed()");
|
||||
Log.w(TAG, "onAuthenticatoinFailed()");
|
||||
FingerprintManagerCompat.AuthenticationCallback callback = this;
|
||||
|
||||
fingerprintPrompt.setImageResource(R.drawable.ic_close_white_48dp);
|
||||
fingerprintPrompt.getBackground().setColorFilter(getResources().getColor(R.color.red_500), PorterDuff.Mode.SRC_IN);
|
||||
@@ -421,5 +392,6 @@ public class PassphrasePromptActivity extends PassphraseActivity {
|
||||
|
||||
fingerprintPrompt.startAnimation(shake);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -11,13 +11,10 @@ import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.fragment.app.Fragment;
|
||||
|
||||
import org.greenrobot.eventbus.EventBus;
|
||||
import org.signal.core.util.logging.Log;
|
||||
import org.signal.core.util.tracing.Tracer;
|
||||
import org.signal.devicetransfer.TransferStatus;
|
||||
import org.thoughtcrime.securesms.crypto.MasterSecretUtil;
|
||||
import org.thoughtcrime.securesms.dependencies.ApplicationDependencies;
|
||||
import org.thoughtcrime.securesms.devicetransfer.olddevice.OldDeviceTransferActivity;
|
||||
import org.thoughtcrime.securesms.jobs.PushNotificationReceiveJob;
|
||||
import org.thoughtcrime.securesms.keyvalue.SignalStore;
|
||||
import org.thoughtcrime.securesms.lock.v2.CreateKbsPinActivity;
|
||||
@@ -35,7 +32,7 @@ import org.thoughtcrime.securesms.util.TextSecurePreferences;
|
||||
import java.util.Locale;
|
||||
|
||||
public abstract class PassphraseRequiredActivity extends BaseActivity implements MasterSecretListener {
|
||||
private static final String TAG = Log.tag(PassphraseRequiredActivity.class);
|
||||
private static final String TAG = PassphraseRequiredActivity.class.getSimpleName();
|
||||
|
||||
public static final String LOCALE_EXTRA = "locale_extra";
|
||||
public static final String NEXT_INTENT_EXTRA = "next_intent";
|
||||
@@ -48,8 +45,6 @@ public abstract class PassphraseRequiredActivity extends BaseActivity implements
|
||||
private static final int STATE_ENTER_SIGNAL_PIN = 5;
|
||||
private static final int STATE_CREATE_PROFILE_NAME = 6;
|
||||
private static final int STATE_CREATE_SIGNAL_PIN = 7;
|
||||
private static final int STATE_TRANSFER_ONGOING = 8;
|
||||
private static final int STATE_TRANSFER_LOCKED = 9;
|
||||
|
||||
private SignalServiceNetworkAccess networkAccess;
|
||||
private BroadcastReceiver clearKeyReceiver;
|
||||
@@ -83,7 +78,7 @@ public abstract class PassphraseRequiredActivity extends BaseActivity implements
|
||||
super.onResume();
|
||||
|
||||
if (networkAccess.isCensored(this)) {
|
||||
ApplicationDependencies.getJobManager().add(new PushNotificationReceiveJob());
|
||||
ApplicationDependencies.getJobManager().add(new PushNotificationReceiveJob(this));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -96,8 +91,8 @@ public abstract class PassphraseRequiredActivity extends BaseActivity implements
|
||||
@Override
|
||||
public void onMasterSecretCleared() {
|
||||
Log.d(TAG, "onMasterSecretCleared()");
|
||||
if (ApplicationDependencies.getAppForegroundObserver().isForegrounded()) routeApplicationState(true);
|
||||
else finish();
|
||||
if (ApplicationContext.getInstance(this).isAppVisible()) routeApplicationState(true);
|
||||
else finish();
|
||||
}
|
||||
|
||||
protected <T extends Fragment> T initFragment(@IdRes int target,
|
||||
@@ -151,8 +146,6 @@ public abstract class PassphraseRequiredActivity extends BaseActivity implements
|
||||
case STATE_ENTER_SIGNAL_PIN: return getEnterSignalPinIntent();
|
||||
case STATE_CREATE_SIGNAL_PIN: return getCreateSignalPinIntent();
|
||||
case STATE_CREATE_PROFILE_NAME: return getCreateProfileNameIntent();
|
||||
case STATE_TRANSFER_ONGOING: return getOldDeviceTransferIntent();
|
||||
case STATE_TRANSFER_LOCKED: return getOldDeviceTransferLockedIntent();
|
||||
default: return null;
|
||||
}
|
||||
}
|
||||
@@ -166,16 +159,12 @@ public abstract class PassphraseRequiredActivity extends BaseActivity implements
|
||||
return STATE_UI_BLOCKING_UPGRADE;
|
||||
} else if (!TextSecurePreferences.hasPromptedPushRegistration(this)) {
|
||||
return STATE_WELCOME_PUSH_SCREEN;
|
||||
} else if (SignalStore.storageService().needsAccountRestore()) {
|
||||
} else if (SignalStore.storageServiceValues().needsAccountRestore()) {
|
||||
return STATE_ENTER_SIGNAL_PIN;
|
||||
} else if (userMustSetProfileName()) {
|
||||
return STATE_CREATE_PROFILE_NAME;
|
||||
} else if (userMustCreateSignalPin()) {
|
||||
return STATE_CREATE_SIGNAL_PIN;
|
||||
} else if (EventBus.getDefault().getStickyEvent(TransferStatus.class) != null && getClass() != OldDeviceTransferActivity.class) {
|
||||
return STATE_TRANSFER_ONGOING;
|
||||
} else if (SignalStore.misc().isOldDeviceTransferLocked()) {
|
||||
return STATE_TRANSFER_LOCKED;
|
||||
} else {
|
||||
return STATE_NORMAL;
|
||||
}
|
||||
@@ -194,9 +183,7 @@ public abstract class PassphraseRequiredActivity extends BaseActivity implements
|
||||
}
|
||||
|
||||
private Intent getPromptPassphraseIntent() {
|
||||
Intent intent = getRoutedIntent(PassphrasePromptActivity.class, getIntent());
|
||||
intent.putExtra(PassphrasePromptActivity.FROM_FOREGROUND, ApplicationDependencies.getAppForegroundObserver().isForegrounded());
|
||||
return intent;
|
||||
return getRoutedIntent(PassphrasePromptActivity.class, getIntent());
|
||||
}
|
||||
|
||||
private Intent getUiBlockingUpgradeIntent() {
|
||||
@@ -207,7 +194,7 @@ public abstract class PassphraseRequiredActivity extends BaseActivity implements
|
||||
}
|
||||
|
||||
private Intent getPushRegistrationIntent() {
|
||||
return RegistrationNavigationActivity.newIntentForNewRegistration(this, getIntent());
|
||||
return RegistrationNavigationActivity.newIntentForNewRegistration(this);
|
||||
}
|
||||
|
||||
private Intent getEnterSignalPinIntent() {
|
||||
@@ -230,19 +217,6 @@ public abstract class PassphraseRequiredActivity extends BaseActivity implements
|
||||
return getRoutedIntent(EditProfileActivity.class, getIntent());
|
||||
}
|
||||
|
||||
private Intent getOldDeviceTransferIntent() {
|
||||
Intent intent = new Intent(this, OldDeviceTransferActivity.class);
|
||||
intent.setFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP);
|
||||
return intent;
|
||||
}
|
||||
|
||||
private @Nullable Intent getOldDeviceTransferLockedIntent() {
|
||||
if (getClass() == MainActivity.class) {
|
||||
return null;
|
||||
}
|
||||
return MainActivity.clearTop(this);
|
||||
}
|
||||
|
||||
private Intent getRoutedIntent(Class<?> destination, @Nullable Intent nextIntent) {
|
||||
final Intent intent = new Intent(this, destination);
|
||||
if (nextIntent != null) intent.putExtra("next_intent", nextIntent);
|
||||
|
||||
@@ -21,7 +21,6 @@ import android.os.Bundle;
|
||||
|
||||
import com.annimon.stream.Stream;
|
||||
|
||||
import org.signal.core.util.logging.Log;
|
||||
import org.thoughtcrime.securesms.contacts.SelectedContact;
|
||||
import org.thoughtcrime.securesms.recipients.RecipientId;
|
||||
|
||||
@@ -39,7 +38,7 @@ public class PushContactSelectionActivity extends ContactSelectionActivity {
|
||||
public static final String KEY_SELECTED_RECIPIENTS = "recipients";
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
private final static String TAG = Log.tag(PushContactSelectionActivity.class);
|
||||
private final static String TAG = PushContactSelectionActivity.class.getSimpleName();
|
||||
|
||||
@Override
|
||||
protected void onCreate(Bundle icicle, boolean ready) {
|
||||
|
||||
@@ -1,48 +0,0 @@
|
||||
package org.thoughtcrime.securesms;
|
||||
|
||||
import android.os.Build;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* Device hardware capability lists.
|
||||
* <p>
|
||||
* Moved outside of ApplicationContext as the indirection was important for API19 support with desugaring: https://issuetracker.google.com/issues/183419297
|
||||
*/
|
||||
final class RtcDeviceLists {
|
||||
|
||||
private RtcDeviceLists() {}
|
||||
|
||||
static Set<String> hardwareAECBlockList() {
|
||||
return new HashSet<String>() {{
|
||||
add("Pixel");
|
||||
add("Pixel XL");
|
||||
add("Moto G5");
|
||||
add("Moto G (5S) Plus");
|
||||
add("Moto G4");
|
||||
add("TA-1053");
|
||||
add("Mi A1");
|
||||
add("Mi A2");
|
||||
add("E5823"); // Sony z5 compact
|
||||
add("Redmi Note 5");
|
||||
add("FP2"); // Fairphone FP2
|
||||
add("MI 5");
|
||||
}};
|
||||
}
|
||||
|
||||
static Set<String> openSlEsAllowList() {
|
||||
return new HashSet<String>() {{
|
||||
add("Pixel");
|
||||
add("Pixel XL");
|
||||
}};
|
||||
}
|
||||
|
||||
static boolean hardwareAECBlocked() {
|
||||
return hardwareAECBlockList().contains(Build.MODEL);
|
||||
}
|
||||
|
||||
static boolean openSLESAllowed() {
|
||||
return openSlEsAllowList().contains(Build.MODEL);
|
||||
}
|
||||
}
|
||||
@@ -20,7 +20,7 @@ import java.net.URISyntaxException;
|
||||
|
||||
public class SmsSendtoActivity extends Activity {
|
||||
|
||||
private static final String TAG = Log.tag(SmsSendtoActivity.class);
|
||||
private static final String TAG = SmsSendtoActivity.class.getSimpleName();
|
||||
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
|
||||
@@ -6,7 +6,6 @@ import android.content.Context;
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
|
||||
import org.signal.core.util.logging.Log;
|
||||
import org.thoughtcrime.securesms.permissions.Permissions;
|
||||
import org.thoughtcrime.securesms.util.CharacterCalculator;
|
||||
import org.thoughtcrime.securesms.util.MmsCharacterCalculator;
|
||||
@@ -26,7 +25,7 @@ import static org.thoughtcrime.securesms.TransportOption.Type;
|
||||
|
||||
public class TransportOptions {
|
||||
|
||||
private static final String TAG = Log.tag(TransportOptions.class);
|
||||
private static final String TAG = TransportOptions.class.getSimpleName();
|
||||
|
||||
private final List<OnTransportChangedListener> listeners = new LinkedList<>();
|
||||
private final Context context;
|
||||
|
||||
@@ -60,12 +60,9 @@ import androidx.appcompat.widget.SwitchCompat;
|
||||
import androidx.fragment.app.Fragment;
|
||||
import androidx.fragment.app.FragmentTransaction;
|
||||
|
||||
import org.signal.core.util.ThreadUtil;
|
||||
import org.signal.core.util.concurrent.SignalExecutors;
|
||||
import org.signal.core.util.logging.Log;
|
||||
import org.thoughtcrime.securesms.color.MaterialColor;
|
||||
import org.thoughtcrime.securesms.components.camera.CameraView;
|
||||
import org.thoughtcrime.securesms.crypto.DatabaseSessionLock;
|
||||
import org.thoughtcrime.securesms.crypto.IdentityKeyParcelable;
|
||||
import org.thoughtcrime.securesms.crypto.IdentityKeyUtil;
|
||||
import org.thoughtcrime.securesms.database.DatabaseFactory;
|
||||
@@ -81,6 +78,7 @@ import org.thoughtcrime.securesms.recipients.LiveRecipient;
|
||||
import org.thoughtcrime.securesms.recipients.Recipient;
|
||||
import org.thoughtcrime.securesms.recipients.RecipientId;
|
||||
import org.thoughtcrime.securesms.storage.StorageSyncHelper;
|
||||
import org.thoughtcrime.securesms.util.DynamicDarkActionBarTheme;
|
||||
import org.thoughtcrime.securesms.util.DynamicTheme;
|
||||
import org.thoughtcrime.securesms.util.FeatureFlags;
|
||||
import org.thoughtcrime.securesms.util.IdentityUtil;
|
||||
@@ -93,13 +91,14 @@ import org.whispersystems.libsignal.fingerprint.Fingerprint;
|
||||
import org.whispersystems.libsignal.fingerprint.FingerprintParsingException;
|
||||
import org.whispersystems.libsignal.fingerprint.FingerprintVersionMismatchException;
|
||||
import org.whispersystems.libsignal.fingerprint.NumericFingerprintGenerator;
|
||||
import org.whispersystems.signalservice.api.SignalSessionLock;
|
||||
import org.whispersystems.signalservice.api.util.UuidUtil;
|
||||
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import java.nio.charset.Charset;
|
||||
import java.util.Locale;
|
||||
|
||||
import static org.whispersystems.libsignal.SessionCipher.SESSION_LOCK;
|
||||
|
||||
/**
|
||||
* Activity for verifying identity keys.
|
||||
*
|
||||
@@ -114,7 +113,7 @@ public class VerifyIdentityActivity extends PassphraseRequiredActivity implement
|
||||
private static final String IDENTITY_EXTRA = "recipient_identity";
|
||||
private static final String VERIFIED_EXTRA = "verified_state";
|
||||
|
||||
private final DynamicTheme dynamicTheme = new DynamicTheme();
|
||||
private final DynamicTheme dynamicTheme = new DynamicDarkActionBarTheme();
|
||||
|
||||
private final VerifyDisplayFragment displayFragment = new VerifyDisplayFragment();
|
||||
private final VerifyScanFragment scanFragment = new VerifyScanFragment();
|
||||
@@ -162,6 +161,11 @@ public class VerifyIdentityActivity extends PassphraseRequiredActivity implement
|
||||
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
|
||||
getSupportActionBar().setTitle(R.string.AndroidManifest__verify_safety_number);
|
||||
|
||||
LiveRecipient recipient = Recipient.live(getIntent().getParcelableExtra(RECIPIENT_EXTRA));
|
||||
recipient.observe(this, r -> setActionBarNotificationBarColor(r.getColor()));
|
||||
|
||||
setActionBarNotificationBarColor(recipient.get().getColor());
|
||||
|
||||
Bundle extras = new Bundle();
|
||||
extras.putParcelable(VerifyDisplayFragment.RECIPIENT_ID, getIntent().getParcelableExtra(RECIPIENT_EXTRA));
|
||||
extras.putParcelable(VerifyDisplayFragment.REMOTE_IDENTITY, getIntent().getParcelableExtra(IDENTITY_EXTRA));
|
||||
@@ -186,7 +190,7 @@ public class VerifyIdentityActivity extends PassphraseRequiredActivity implement
|
||||
|
||||
@Override
|
||||
public void onQrDataFound(final String data) {
|
||||
ThreadUtil.runOnMain(() -> {
|
||||
Util.runOnMain(() -> {
|
||||
((Vibrator)getSystemService(Context.VIBRATOR_SERVICE)).vibrate(50);
|
||||
|
||||
getSupportFragmentManager().popBackStack();
|
||||
@@ -302,7 +306,6 @@ public class VerifyIdentityActivity extends PassphraseRequiredActivity implement
|
||||
byte[] localId;
|
||||
byte[] remoteId;
|
||||
|
||||
//noinspection WrongThread
|
||||
Recipient resolved = recipient.resolve();
|
||||
|
||||
if (FeatureFlags.verifyV2() && resolved.getUuid().isPresent()) {
|
||||
@@ -619,35 +622,36 @@ public class VerifyIdentityActivity extends PassphraseRequiredActivity implement
|
||||
|
||||
@Override
|
||||
public void onCheckedChanged(CompoundButton buttonView, final boolean isChecked) {
|
||||
final Recipient recipient = this.recipient.get();
|
||||
final RecipientId recipientId = recipient.getId();
|
||||
new AsyncTask<Recipient, Void, Void>() {
|
||||
@Override
|
||||
protected Void doInBackground(Recipient... params) {
|
||||
synchronized (SESSION_LOCK) {
|
||||
if (isChecked) {
|
||||
Log.i(TAG, "Saving identity: " + params[0].getId());
|
||||
DatabaseFactory.getIdentityDatabase(getActivity())
|
||||
.saveIdentity(params[0].getId(),
|
||||
remoteIdentity,
|
||||
VerifiedStatus.VERIFIED, false,
|
||||
System.currentTimeMillis(), true);
|
||||
} else {
|
||||
DatabaseFactory.getIdentityDatabase(getActivity())
|
||||
.setVerified(params[0].getId(),
|
||||
remoteIdentity,
|
||||
VerifiedStatus.DEFAULT);
|
||||
}
|
||||
|
||||
SignalExecutors.BOUNDED.execute(() -> {
|
||||
try (SignalSessionLock.Lock unused = DatabaseSessionLock.INSTANCE.acquire()) {
|
||||
if (isChecked) {
|
||||
Log.i(TAG, "Saving identity: " + recipientId);
|
||||
DatabaseFactory.getIdentityDatabase(getActivity())
|
||||
.saveIdentity(recipientId,
|
||||
remoteIdentity,
|
||||
VerifiedStatus.VERIFIED, false,
|
||||
System.currentTimeMillis(), true);
|
||||
} else {
|
||||
DatabaseFactory.getIdentityDatabase(getActivity())
|
||||
.setVerified(recipientId,
|
||||
remoteIdentity,
|
||||
VerifiedStatus.DEFAULT);
|
||||
ApplicationDependencies.getJobManager()
|
||||
.add(new MultiDeviceVerifiedUpdateJob(recipient.getId(),
|
||||
remoteIdentity,
|
||||
isChecked ? VerifiedStatus.VERIFIED :
|
||||
VerifiedStatus.DEFAULT));
|
||||
StorageSyncHelper.scheduleSyncForDataChange();
|
||||
|
||||
IdentityUtil.markIdentityVerified(getActivity(), recipient.get(), isChecked, false);
|
||||
}
|
||||
|
||||
ApplicationDependencies.getJobManager()
|
||||
.add(new MultiDeviceVerifiedUpdateJob(recipientId,
|
||||
remoteIdentity,
|
||||
isChecked ? VerifiedStatus.VERIFIED
|
||||
: VerifiedStatus.DEFAULT));
|
||||
StorageSyncHelper.scheduleSyncForDataChange();
|
||||
|
||||
IdentityUtil.markIdentityVerified(getActivity(), recipient, isChecked, false);
|
||||
return null;
|
||||
}
|
||||
});
|
||||
}.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, recipient.get());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -27,7 +27,9 @@ import android.media.AudioManager;
|
||||
import android.os.Build;
|
||||
import android.os.Bundle;
|
||||
import android.util.Rational;
|
||||
import android.view.View;
|
||||
import android.view.Window;
|
||||
import android.view.WindowInsetsController;
|
||||
import android.view.WindowManager;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
@@ -35,13 +37,14 @@ import androidx.appcompat.app.AlertDialog;
|
||||
import androidx.appcompat.app.AppCompatDelegate;
|
||||
import androidx.core.content.ContextCompat;
|
||||
import androidx.lifecycle.ViewModelProviders;
|
||||
import androidx.transition.Transition;
|
||||
import androidx.transition.TransitionListenerAdapter;
|
||||
|
||||
import org.greenrobot.eventbus.EventBus;
|
||||
import org.greenrobot.eventbus.Subscribe;
|
||||
import org.greenrobot.eventbus.ThreadMode;
|
||||
import org.signal.core.util.logging.Log;
|
||||
import org.thoughtcrime.securesms.components.TooltipPopup;
|
||||
import org.thoughtcrime.securesms.components.sensors.DeviceOrientationMonitor;
|
||||
import org.thoughtcrime.securesms.components.webrtc.CallParticipantsListUpdatePopupWindow;
|
||||
import org.thoughtcrime.securesms.components.webrtc.CallParticipantsState;
|
||||
import org.thoughtcrime.securesms.components.webrtc.GroupCallSafetyNumberChangeNotificationUtil;
|
||||
@@ -50,20 +53,22 @@ import org.thoughtcrime.securesms.components.webrtc.WebRtcCallView;
|
||||
import org.thoughtcrime.securesms.components.webrtc.WebRtcCallViewModel;
|
||||
import org.thoughtcrime.securesms.components.webrtc.participantslist.CallParticipantsListDialog;
|
||||
import org.thoughtcrime.securesms.conversation.ui.error.SafetyNumberChangeDialog;
|
||||
import org.thoughtcrime.securesms.dependencies.ApplicationDependencies;
|
||||
import org.thoughtcrime.securesms.events.WebRtcViewModel;
|
||||
import org.thoughtcrime.securesms.messagerequests.CalleeMustAcceptMessageRequestActivity;
|
||||
import org.thoughtcrime.securesms.permissions.Permissions;
|
||||
import org.thoughtcrime.securesms.recipients.Recipient;
|
||||
import org.thoughtcrime.securesms.recipients.RecipientId;
|
||||
import org.thoughtcrime.securesms.service.webrtc.SignalCallManager;
|
||||
import org.thoughtcrime.securesms.ringrtc.RemotePeer;
|
||||
import org.thoughtcrime.securesms.service.WebRtcCallService;
|
||||
import org.thoughtcrime.securesms.sms.MessageSender;
|
||||
import org.thoughtcrime.securesms.util.EllapsedTimeFormatter;
|
||||
import org.thoughtcrime.securesms.util.FullscreenHelper;
|
||||
import org.thoughtcrime.securesms.util.TextSecurePreferences;
|
||||
import org.thoughtcrime.securesms.util.Util;
|
||||
import org.thoughtcrime.securesms.util.WindowUtil;
|
||||
import org.whispersystems.libsignal.IdentityKey;
|
||||
import org.whispersystems.signalservice.api.messages.calls.HangupMessage;
|
||||
import org.whispersystems.signalservice.api.messages.calls.OfferMessage;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@@ -80,7 +85,6 @@ public class WebRtcCallActivity extends BaseActivity implements SafetyNumberChan
|
||||
public static final String EXTRA_ENABLE_VIDEO_IF_AVAILABLE = WebRtcCallActivity.class.getCanonicalName() + ".ENABLE_VIDEO_IF_AVAILABLE";
|
||||
|
||||
private CallParticipantsListUpdatePopupWindow participantUpdateWindow;
|
||||
private DeviceOrientationMonitor deviceOrientationMonitor;
|
||||
|
||||
private FullscreenHelper fullscreenHelper;
|
||||
private WebRtcCallView callScreen;
|
||||
@@ -140,7 +144,7 @@ public class WebRtcCallActivity extends BaseActivity implements SafetyNumberChan
|
||||
Log.i(TAG, "onPause");
|
||||
super.onPause();
|
||||
|
||||
if (!isInPipMode() || isFinishing()) {
|
||||
if (!isInPipMode()) {
|
||||
EventBus.getDefault().unregister(this);
|
||||
}
|
||||
|
||||
@@ -157,24 +161,18 @@ public class WebRtcCallActivity extends BaseActivity implements SafetyNumberChan
|
||||
Log.i(TAG, "onStop");
|
||||
super.onStop();
|
||||
|
||||
if (!isInPipMode() || isFinishing()) {
|
||||
EventBus.getDefault().unregister(this);
|
||||
}
|
||||
EventBus.getDefault().unregister(this);
|
||||
|
||||
if (!viewModel.isCallStarting()) {
|
||||
CallParticipantsState state = viewModel.getCallParticipantsState().getValue();
|
||||
if (state != null && state.getCallState().isPreJoinOrNetworkUnavailable()) {
|
||||
ApplicationDependencies.getSignalCallManager().cancelPreJoin();
|
||||
Intent intent = new Intent(this, WebRtcCallService.class);
|
||||
intent.setAction(WebRtcCallService.ACTION_CANCEL_PRE_JOIN_CALL);
|
||||
startService(intent);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onDestroy() {
|
||||
super.onDestroy();
|
||||
EventBus.getDefault().unregister(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
|
||||
Permissions.onRequestPermissionsResult(this, requestCode, permissions, grantResults);
|
||||
@@ -242,12 +240,7 @@ public class WebRtcCallActivity extends BaseActivity implements SafetyNumberChan
|
||||
}
|
||||
|
||||
private void initializeViewModel() {
|
||||
deviceOrientationMonitor = new DeviceOrientationMonitor(this);
|
||||
getLifecycle().addObserver(deviceOrientationMonitor);
|
||||
|
||||
WebRtcCallViewModel.Factory factory = new WebRtcCallViewModel.Factory(deviceOrientationMonitor);
|
||||
|
||||
viewModel = ViewModelProviders.of(this, factory).get(WebRtcCallViewModel.class);
|
||||
viewModel = ViewModelProviders.of(this).get(WebRtcCallViewModel.class);
|
||||
viewModel.setIsInPipMode(isInPipMode());
|
||||
viewModel.getMicrophoneEnabled().observe(this, callScreen::setMicEnabled);
|
||||
viewModel.getWebRtcControls().observe(this, callScreen::setWebRtcControls);
|
||||
@@ -263,25 +256,12 @@ public class WebRtcCallActivity extends BaseActivity implements SafetyNumberChan
|
||||
CallParticipantsState state = viewModel.getCallParticipantsState().getValue();
|
||||
if (state != null) {
|
||||
if (state.needsNewRequestSizes()) {
|
||||
ApplicationDependencies.getSignalCallManager().updateRenderedResolutions();
|
||||
Intent intent = new Intent(WebRtcCallActivity.this, WebRtcCallService.class);
|
||||
intent.setAction(WebRtcCallService.ACTION_GROUP_UPDATE_RENDERED_RESOLUTIONS);
|
||||
startService(intent);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
viewModel.getOrientation().observe(this, orientation -> {
|
||||
ApplicationDependencies.getSignalCallManager().orientationChanged(orientation.getDegrees());
|
||||
|
||||
switch (orientation) {
|
||||
case LANDSCAPE_LEFT_EDGE:
|
||||
callScreen.rotateControls(90);
|
||||
break;
|
||||
case LANDSCAPE_RIGHT_EDGE:
|
||||
callScreen.rotateControls(-90);
|
||||
break;
|
||||
case PORTRAIT_BOTTOM_EDGE:
|
||||
callScreen.rotateControls(0);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void handleViewModelEvent(@NonNull WebRtcCallViewModel.Event event) {
|
||||
@@ -328,19 +308,30 @@ public class WebRtcCallActivity extends BaseActivity implements SafetyNumberChan
|
||||
}
|
||||
|
||||
private void handleSetAudioHandset() {
|
||||
ApplicationDependencies.getSignalCallManager().setAudioSpeaker(false);
|
||||
Intent intent = new Intent(this, WebRtcCallService.class);
|
||||
intent.setAction(WebRtcCallService.ACTION_SET_AUDIO_SPEAKER);
|
||||
startService(intent);
|
||||
}
|
||||
|
||||
private void handleSetAudioSpeaker() {
|
||||
ApplicationDependencies.getSignalCallManager().setAudioSpeaker(true);
|
||||
Intent intent = new Intent(this, WebRtcCallService.class);
|
||||
intent.setAction(WebRtcCallService.ACTION_SET_AUDIO_SPEAKER);
|
||||
intent.putExtra(WebRtcCallService.EXTRA_SPEAKER, true);
|
||||
startService(intent);
|
||||
}
|
||||
|
||||
private void handleSetAudioBluetooth() {
|
||||
ApplicationDependencies.getSignalCallManager().setAudioBluetooth(true);
|
||||
Intent intent = new Intent(this, WebRtcCallService.class);
|
||||
intent.setAction(WebRtcCallService.ACTION_SET_AUDIO_BLUETOOTH);
|
||||
intent.putExtra(WebRtcCallService.EXTRA_BLUETOOTH, true);
|
||||
startService(intent);
|
||||
}
|
||||
|
||||
private void handleSetMuteAudio(boolean enabled) {
|
||||
ApplicationDependencies.getSignalCallManager().setMuteAudio(enabled);
|
||||
Intent intent = new Intent(this, WebRtcCallService.class);
|
||||
intent.setAction(WebRtcCallService.ACTION_SET_MUTE_AUDIO);
|
||||
intent.putExtra(WebRtcCallService.EXTRA_MUTE, enabled);
|
||||
startService(intent);
|
||||
}
|
||||
|
||||
private void handleSetMuteVideo(boolean muted) {
|
||||
@@ -354,13 +345,20 @@ public class WebRtcCallActivity extends BaseActivity implements SafetyNumberChan
|
||||
.ifNecessary()
|
||||
.withRationaleDialog(getString(R.string.WebRtcCallActivity__to_call_s_signal_needs_access_to_your_camera, recipientDisplayName), R.drawable.ic_video_solid_24_tinted)
|
||||
.withPermanentDenialDialog(getString(R.string.WebRtcCallActivity__to_call_s_signal_needs_access_to_your_camera, recipientDisplayName))
|
||||
.onAllGranted(() -> ApplicationDependencies.getSignalCallManager().setMuteVideo(!muted))
|
||||
.onAllGranted(() -> {
|
||||
Intent intent = new Intent(this, WebRtcCallService.class);
|
||||
intent.setAction(WebRtcCallService.ACTION_SET_ENABLE_VIDEO);
|
||||
intent.putExtra(WebRtcCallService.EXTRA_ENABLE, !muted);
|
||||
startService(intent);
|
||||
})
|
||||
.execute();
|
||||
}
|
||||
}
|
||||
|
||||
private void handleFlipCamera() {
|
||||
ApplicationDependencies.getSignalCallManager().flipCamera();
|
||||
Intent intent = new Intent(this, WebRtcCallService.class);
|
||||
intent.setAction(WebRtcCallService.ACTION_FLIP_CAMERA);
|
||||
startService(intent);
|
||||
}
|
||||
|
||||
private void handleAnswerWithAudio() {
|
||||
@@ -377,7 +375,9 @@ public class WebRtcCallActivity extends BaseActivity implements SafetyNumberChan
|
||||
callScreen.setRecipient(recipient);
|
||||
callScreen.setStatus(getString(R.string.RedPhone_answering));
|
||||
|
||||
ApplicationDependencies.getSignalCallManager().acceptCall(false);
|
||||
Intent intent = new Intent(this, WebRtcCallService.class);
|
||||
intent.setAction(WebRtcCallService.ACTION_ACCEPT_CALL);
|
||||
startService(intent);
|
||||
})
|
||||
.onAnyDenied(this::handleDenyCall)
|
||||
.execute();
|
||||
@@ -398,7 +398,10 @@ public class WebRtcCallActivity extends BaseActivity implements SafetyNumberChan
|
||||
callScreen.setRecipient(recipient);
|
||||
callScreen.setStatus(getString(R.string.RedPhone_answering));
|
||||
|
||||
ApplicationDependencies.getSignalCallManager().acceptCall(true);
|
||||
Intent intent = new Intent(this, WebRtcCallService.class);
|
||||
intent.setAction(WebRtcCallService.ACTION_ACCEPT_CALL);
|
||||
intent.putExtra(WebRtcCallService.EXTRA_ANSWER_WITH_VIDEO, true);
|
||||
startService(intent);
|
||||
|
||||
handleSetMuteVideo(false);
|
||||
})
|
||||
@@ -411,7 +414,9 @@ public class WebRtcCallActivity extends BaseActivity implements SafetyNumberChan
|
||||
Recipient recipient = viewModel.getRecipient().get();
|
||||
|
||||
if (!recipient.equals(Recipient.UNKNOWN)) {
|
||||
ApplicationDependencies.getSignalCallManager().denyCall();
|
||||
Intent intent = new Intent(this, WebRtcCallService.class);
|
||||
intent.setAction(WebRtcCallService.ACTION_DENY_CALL);
|
||||
startService(intent);
|
||||
|
||||
callScreen.setRecipient(recipient);
|
||||
callScreen.setStatus(getString(R.string.RedPhone_ending_call));
|
||||
@@ -421,7 +426,9 @@ public class WebRtcCallActivity extends BaseActivity implements SafetyNumberChan
|
||||
|
||||
private void handleEndCall() {
|
||||
Log.i(TAG, "Hangup pressed, handling termination now...");
|
||||
ApplicationDependencies.getSignalCallManager().localHangup();
|
||||
Intent intent = new Intent(WebRtcCallActivity.this, WebRtcCallService.class);
|
||||
intent.setAction(WebRtcCallService.ACTION_LOCAL_HANGUP);
|
||||
startService(intent);
|
||||
}
|
||||
|
||||
private void handleOutgoingCall(@NonNull WebRtcViewModel event) {
|
||||
@@ -452,7 +459,7 @@ public class WebRtcCallActivity extends BaseActivity implements SafetyNumberChan
|
||||
private void handleCallBusy() {
|
||||
EventBus.getDefault().removeStickyEvent(WebRtcViewModel.class);
|
||||
callScreen.setStatus(getString(R.string.RedPhone_busy));
|
||||
delayedFinish(SignalCallManager.BUSY_TONE_LENGTH);
|
||||
delayedFinish(WebRtcCallService.BUSY_TONE_LENGTH);
|
||||
}
|
||||
|
||||
private void handleCallConnected(@NonNull WebRtcViewModel event) {
|
||||
@@ -490,7 +497,6 @@ public class WebRtcCallActivity extends BaseActivity implements SafetyNumberChan
|
||||
final Recipient recipient = event.getRemoteParticipants().get(0).getRecipient();
|
||||
|
||||
if (theirKey == null) {
|
||||
Log.w(TAG, "Untrusted identity without an identity key, terminating call.");
|
||||
handleTerminate(recipient, HangupMessage.Type.NORMAL);
|
||||
}
|
||||
|
||||
@@ -509,7 +515,7 @@ public class WebRtcCallActivity extends BaseActivity implements SafetyNumberChan
|
||||
}
|
||||
|
||||
private void updateGroupMembersForGroupCall() {
|
||||
ApplicationDependencies.getSignalCallManager().requestUpdateGroupMembers();
|
||||
startService(new Intent(this, WebRtcCallService.class).setAction(WebRtcCallService.ACTION_GROUP_REQUEST_UPDATE_MEMBERS));
|
||||
}
|
||||
|
||||
private void updateSpeakerHint(boolean showSpeakerHint) {
|
||||
@@ -523,13 +529,11 @@ public class WebRtcCallActivity extends BaseActivity implements SafetyNumberChan
|
||||
@Override
|
||||
public void onSendAnywayAfterSafetyNumberChange(@NonNull List<RecipientId> changedRecipients) {
|
||||
CallParticipantsState state = viewModel.getCallParticipantsState().getValue();
|
||||
|
||||
if (state == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (state.getGroupCallState().isConnected()) {
|
||||
ApplicationDependencies.getSignalCallManager().groupApproveSafetyChange(changedRecipients);
|
||||
Intent intent = new Intent(this, WebRtcCallService.class);
|
||||
intent.setAction(WebRtcCallService.ACTION_GROUP_APPROVE_SAFETY_CHANGE)
|
||||
.putExtra(WebRtcCallService.EXTRA_RECIPIENT_IDS, RecipientId.toSerializedList(changedRecipients));
|
||||
startService(intent);
|
||||
} else {
|
||||
viewModel.startCall(state.getLocalParticipant().isVideoEnabled());
|
||||
}
|
||||
@@ -543,7 +547,9 @@ public class WebRtcCallActivity extends BaseActivity implements SafetyNumberChan
|
||||
CallParticipantsState state = viewModel.getCallParticipantsState().getValue();
|
||||
if (state != null && state.getGroupCallState().isNotIdle()) {
|
||||
if (state.getCallState().isPreJoinOrNetworkUnavailable()) {
|
||||
ApplicationDependencies.getSignalCallManager().cancelPreJoin();
|
||||
Intent intent = new Intent(this, WebRtcCallService.class);
|
||||
intent.setAction(WebRtcCallService.ACTION_CANCEL_PRE_JOIN_CALL);
|
||||
startService(intent);
|
||||
finish();
|
||||
} else {
|
||||
handleEndCall();
|
||||
@@ -609,11 +615,11 @@ public class WebRtcCallActivity extends BaseActivity implements SafetyNumberChan
|
||||
private void startCall(boolean isVideoCall) {
|
||||
enableVideoIfAvailable = isVideoCall;
|
||||
|
||||
if (isVideoCall) {
|
||||
ApplicationDependencies.getSignalCallManager().startOutgoingVideoCall(viewModel.getRecipient().get());
|
||||
} else {
|
||||
ApplicationDependencies.getSignalCallManager().startOutgoingAudioCall(viewModel.getRecipient().get());
|
||||
}
|
||||
Intent intent = new Intent(WebRtcCallActivity.this, WebRtcCallService.class);
|
||||
intent.setAction(WebRtcCallService.ACTION_OUTGOING_CALL)
|
||||
.putExtra(WebRtcCallService.EXTRA_REMOTE_PEER, new RemotePeer(viewModel.getRecipient().getId()))
|
||||
.putExtra(WebRtcCallService.EXTRA_OFFER_TYPE, (isVideoCall ? OfferMessage.Type.VIDEO_CALL : OfferMessage.Type.AUDIO_CALL).getCode());
|
||||
startService(intent);
|
||||
|
||||
MessageSender.onMessageSent();
|
||||
}
|
||||
|
||||
@@ -40,7 +40,6 @@ public abstract class Attachment {
|
||||
|
||||
private final boolean voiceNote;
|
||||
private final boolean borderless;
|
||||
private final boolean videoGif;
|
||||
private final int width;
|
||||
private final int height;
|
||||
private final boolean quote;
|
||||
@@ -73,7 +72,6 @@ public abstract class Attachment {
|
||||
@Nullable String fastPreflightId,
|
||||
boolean voiceNote,
|
||||
boolean borderless,
|
||||
boolean videoGif,
|
||||
int width,
|
||||
int height,
|
||||
boolean quote,
|
||||
@@ -96,7 +94,6 @@ public abstract class Attachment {
|
||||
this.fastPreflightId = fastPreflightId;
|
||||
this.voiceNote = voiceNote;
|
||||
this.borderless = borderless;
|
||||
this.videoGif = videoGif;
|
||||
this.width = width;
|
||||
this.height = height;
|
||||
this.quote = quote;
|
||||
@@ -111,8 +108,6 @@ public abstract class Attachment {
|
||||
@Nullable
|
||||
public abstract Uri getUri();
|
||||
|
||||
public abstract @Nullable Uri getPublicUri();
|
||||
|
||||
public int getTransferState() {
|
||||
return transferState;
|
||||
}
|
||||
@@ -173,10 +168,6 @@ public abstract class Attachment {
|
||||
return borderless;
|
||||
}
|
||||
|
||||
public boolean isVideoGif() {
|
||||
return videoGif;
|
||||
}
|
||||
|
||||
public int getWidth() {
|
||||
return width;
|
||||
}
|
||||
|
||||
@@ -36,7 +36,6 @@ public class DatabaseAttachment extends Attachment {
|
||||
String fastPreflightId,
|
||||
boolean voiceNote,
|
||||
boolean borderless,
|
||||
boolean videoGif,
|
||||
int width,
|
||||
int height,
|
||||
boolean quote,
|
||||
@@ -48,7 +47,7 @@ public class DatabaseAttachment extends Attachment {
|
||||
int displayOrder,
|
||||
long uploadTimestamp)
|
||||
{
|
||||
super(contentType, transferProgress, size, fileName, cdnNumber, location, key, relay, digest, fastPreflightId, voiceNote, borderless, videoGif, width, height, quote, uploadTimestamp, caption, stickerLocator, blurHash, audioHash, transformProperties);
|
||||
super(contentType, transferProgress, size, fileName, cdnNumber, location, key, relay, digest, fastPreflightId, voiceNote, borderless, width, height, quote, uploadTimestamp, caption, stickerLocator, blurHash, audioHash, transformProperties);
|
||||
this.attachmentId = attachmentId;
|
||||
this.hasData = hasData;
|
||||
this.hasThumbnail = hasThumbnail;
|
||||
@@ -66,15 +65,6 @@ public class DatabaseAttachment extends Attachment {
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public @Nullable Uri getPublicUri() {
|
||||
if (hasData) {
|
||||
return PartAuthority.getAttachmentPublicUri(getUri());
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public AttachmentId getAttachmentId() {
|
||||
return attachmentId;
|
||||
}
|
||||
|
||||
@@ -11,7 +11,7 @@ import org.thoughtcrime.securesms.database.MmsDatabase;
|
||||
public class MmsNotificationAttachment extends Attachment {
|
||||
|
||||
public MmsNotificationAttachment(int status, long size) {
|
||||
super("application/mms", getTransferStateFromStatus(status), size, null, 0, null, null, null, null, null, false, false, false, 0, 0, false, 0, null, null, null, null, null);
|
||||
super("application/mms", getTransferStateFromStatus(status), size, null, 0, null, null, null, null, null, false, false, 0, 0, false, 0, null, null, null, null, null);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@@ -20,11 +20,6 @@ public class MmsNotificationAttachment extends Attachment {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public @Nullable Uri getPublicUri() {
|
||||
return null;
|
||||
}
|
||||
|
||||
private static int getTransferStateFromStatus(int status) {
|
||||
if (status == MmsDatabase.Status.DOWNLOAD_INITIALIZED ||
|
||||
status == MmsDatabase.Status.DOWNLOAD_NO_CONNECTIVITY)
|
||||
|
||||
@@ -30,7 +30,6 @@ public class PointerAttachment extends Attachment {
|
||||
@Nullable String fastPreflightId,
|
||||
boolean voiceNote,
|
||||
boolean borderless,
|
||||
boolean videoGif,
|
||||
int width,
|
||||
int height,
|
||||
long uploadTimestamp,
|
||||
@@ -38,7 +37,7 @@ public class PointerAttachment extends Attachment {
|
||||
@Nullable StickerLocator stickerLocator,
|
||||
@Nullable BlurHash blurHash)
|
||||
{
|
||||
super(contentType, transferState, size, fileName, cdnNumber, location, key, relay, digest, fastPreflightId, voiceNote, borderless, videoGif, width, height, false, uploadTimestamp, caption, stickerLocator, blurHash, null, null);
|
||||
super(contentType, transferState, size, fileName, cdnNumber, location, key, relay, digest, fastPreflightId, voiceNote, borderless, width, height, false, uploadTimestamp, caption, stickerLocator, blurHash, null, null);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@@ -47,11 +46,6 @@ public class PointerAttachment extends Attachment {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public @Nullable Uri getPublicUri() {
|
||||
return null;
|
||||
}
|
||||
|
||||
public static List<Attachment> forPointers(Optional<List<SignalServiceAttachment>> pointers) {
|
||||
List<Attachment> results = new LinkedList<>();
|
||||
|
||||
@@ -112,7 +106,6 @@ public class PointerAttachment extends Attachment {
|
||||
fastPreflightId,
|
||||
pointer.get().asPointer().getVoiceNote(),
|
||||
pointer.get().asPointer().isBorderless(),
|
||||
pointer.get().asPointer().isGif(),
|
||||
pointer.get().asPointer().getWidth(),
|
||||
pointer.get().asPointer().getHeight(),
|
||||
pointer.get().asPointer().getUploadTimestamp(),
|
||||
@@ -137,7 +130,6 @@ public class PointerAttachment extends Attachment {
|
||||
null,
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
thumbnail != null ? thumbnail.asPointer().getWidth() : 0,
|
||||
thumbnail != null ? thumbnail.asPointer().getHeight() : 0,
|
||||
thumbnail != null ? thumbnail.asPointer().getUploadTimestamp() : 0,
|
||||
|
||||
@@ -16,16 +16,11 @@ import org.thoughtcrime.securesms.database.AttachmentDatabase;
|
||||
public class TombstoneAttachment extends Attachment {
|
||||
|
||||
public TombstoneAttachment(@NonNull String contentType, boolean quote) {
|
||||
super(contentType, AttachmentDatabase.TRANSFER_PROGRESS_DONE, 0, null, 0, null, null, null, null, null, false, false, false, 0, 0, quote, 0, null, null, null, null, null);
|
||||
super(contentType, AttachmentDatabase.TRANSFER_PROGRESS_DONE, 0, null, 0, null, null, null, null, null, false, false, 0, 0, quote, 0, null, null, null, null, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public @Nullable Uri getUri() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public @Nullable Uri getPublicUri() {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -21,7 +21,6 @@ public class UriAttachment extends Attachment {
|
||||
@Nullable String fileName,
|
||||
boolean voiceNote,
|
||||
boolean borderless,
|
||||
boolean videoGif,
|
||||
boolean quote,
|
||||
@Nullable String caption,
|
||||
@Nullable StickerLocator stickerLocator,
|
||||
@@ -29,7 +28,7 @@ public class UriAttachment extends Attachment {
|
||||
@Nullable AudioHash audioHash,
|
||||
@Nullable TransformProperties transformProperties)
|
||||
{
|
||||
this(uri, contentType, transferState, size, 0, 0, fileName, null, voiceNote, borderless, videoGif, quote, caption, stickerLocator, blurHash, audioHash, transformProperties);
|
||||
this(uri, contentType, transferState, size, 0, 0, fileName, null, voiceNote, borderless, quote, caption, stickerLocator, blurHash, audioHash, transformProperties);
|
||||
}
|
||||
|
||||
public UriAttachment(@NonNull Uri dataUri,
|
||||
@@ -42,7 +41,6 @@ public class UriAttachment extends Attachment {
|
||||
@Nullable String fastPreflightId,
|
||||
boolean voiceNote,
|
||||
boolean borderless,
|
||||
boolean videoGif,
|
||||
boolean quote,
|
||||
@Nullable String caption,
|
||||
@Nullable StickerLocator stickerLocator,
|
||||
@@ -50,7 +48,7 @@ public class UriAttachment extends Attachment {
|
||||
@Nullable AudioHash audioHash,
|
||||
@Nullable TransformProperties transformProperties)
|
||||
{
|
||||
super(contentType, transferState, size, fileName, 0, null, null, null, null, fastPreflightId, voiceNote, borderless, videoGif, width, height, quote, 0, caption, stickerLocator, blurHash, audioHash, transformProperties);
|
||||
super(contentType, transferState, size, fileName, 0, null, null, null, null, fastPreflightId, voiceNote, borderless, width, height, quote, 0, caption, stickerLocator, blurHash, audioHash, transformProperties);
|
||||
this.dataUri = dataUri;
|
||||
}
|
||||
|
||||
@@ -60,11 +58,6 @@ public class UriAttachment extends Attachment {
|
||||
return dataUri;
|
||||
}
|
||||
|
||||
@Override
|
||||
public @Nullable Uri getPublicUri() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object other) {
|
||||
return other != null && other instanceof UriAttachment && ((UriAttachment) other).dataUri.equals(this.dataUri);
|
||||
|
||||
@@ -20,7 +20,7 @@ import java.nio.ByteBuffer;
|
||||
@TargetApi(Build.VERSION_CODES.JELLY_BEAN)
|
||||
public class AudioCodec {
|
||||
|
||||
private static final String TAG = Log.tag(AudioCodec.class);
|
||||
private static final String TAG = AudioCodec.class.getSimpleName();
|
||||
|
||||
private static final int SAMPLE_RATE = 44100;
|
||||
private static final int SAMPLE_RATE_INDEX = 4;
|
||||
|
||||
@@ -8,11 +8,11 @@ import android.os.ParcelFileDescriptor;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
|
||||
import org.signal.core.util.ThreadUtil;
|
||||
import org.signal.core.util.concurrent.SignalExecutors;
|
||||
import org.signal.core.util.logging.Log;
|
||||
import org.thoughtcrime.securesms.providers.BlobProvider;
|
||||
import org.thoughtcrime.securesms.util.MediaUtil;
|
||||
import org.thoughtcrime.securesms.util.Util;
|
||||
import org.thoughtcrime.securesms.util.concurrent.ListenableFuture;
|
||||
import org.thoughtcrime.securesms.util.concurrent.SettableFuture;
|
||||
import org.whispersystems.libsignal.util.Pair;
|
||||
@@ -23,7 +23,7 @@ import java.util.concurrent.ExecutorService;
|
||||
@TargetApi(Build.VERSION_CODES.JELLY_BEAN)
|
||||
public class AudioRecorder {
|
||||
|
||||
private static final String TAG = Log.tag(AudioRecorder.class);
|
||||
private static final String TAG = AudioRecorder.class.getSimpleName();
|
||||
|
||||
private static final ExecutorService executor = SignalExecutors.newCachedSingleThreadExecutor("signal-AudioRecorder");
|
||||
|
||||
@@ -90,10 +90,10 @@ public class AudioRecorder {
|
||||
}
|
||||
|
||||
private <T> void sendToFuture(final SettableFuture<T> future, final Exception exception) {
|
||||
ThreadUtil.runOnMain(() -> future.setException(exception));
|
||||
Util.runOnMain(() -> future.setException(exception));
|
||||
}
|
||||
|
||||
private <T> void sendToFuture(final SettableFuture<T> future, final T result) {
|
||||
ThreadUtil.runOnMain(() -> future.set(result));
|
||||
Util.runOnMain(() -> future.set(result));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,7 +16,6 @@ import androidx.core.util.Consumer;
|
||||
|
||||
import com.google.protobuf.ByteString;
|
||||
|
||||
import org.signal.core.util.ThreadUtil;
|
||||
import org.signal.core.util.concurrent.SignalExecutors;
|
||||
import org.signal.core.util.logging.Log;
|
||||
import org.thoughtcrime.securesms.attachments.Attachment;
|
||||
@@ -27,6 +26,7 @@ import org.thoughtcrime.securesms.database.model.databaseprotos.AudioWaveFormDat
|
||||
import org.thoughtcrime.securesms.media.DecryptableUriMediaInput;
|
||||
import org.thoughtcrime.securesms.media.MediaInput;
|
||||
import org.thoughtcrime.securesms.mms.AudioSlide;
|
||||
import org.thoughtcrime.securesms.util.Util;
|
||||
import org.thoughtcrime.securesms.util.concurrent.SerialExecutor;
|
||||
|
||||
import java.io.IOException;
|
||||
@@ -61,13 +61,13 @@ public final class AudioWaveForm {
|
||||
|
||||
if (uri == null) {
|
||||
Log.w(TAG, "No uri");
|
||||
ThreadUtil.runOnMain(onFailure);
|
||||
Util.runOnMain(onFailure);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!(attachment instanceof DatabaseAttachment)) {
|
||||
Log.i(TAG, "Not yet in database");
|
||||
ThreadUtil.runOnMain(onFailure);
|
||||
Util.runOnMain(onFailure);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -75,7 +75,7 @@ public final class AudioWaveForm {
|
||||
AudioFileInfo cached = WAVE_FORM_CACHE.get(cacheKey);
|
||||
if (cached != null) {
|
||||
Log.i(TAG, "Loaded wave form from cache " + cacheKey);
|
||||
ThreadUtil.runOnMain(() -> onSuccess.accept(cached));
|
||||
Util.runOnMain(() -> onSuccess.accept(cached));
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -83,7 +83,7 @@ public final class AudioWaveForm {
|
||||
AudioFileInfo cachedInExecutor = WAVE_FORM_CACHE.get(cacheKey);
|
||||
if (cachedInExecutor != null) {
|
||||
Log.i(TAG, "Loaded wave form from cache inside executor" + cacheKey);
|
||||
ThreadUtil.runOnMain(() -> onSuccess.accept(cachedInExecutor));
|
||||
Util.runOnMain(() -> onSuccess.accept(cachedInExecutor));
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -92,14 +92,14 @@ public final class AudioWaveForm {
|
||||
AudioFileInfo audioFileInfo = AudioFileInfo.fromDatabaseProtobuf(audioHash.getAudioWaveForm());
|
||||
if (audioFileInfo.waveForm.length == 0) {
|
||||
Log.w(TAG, "Recovering from a wave form generation error " + cacheKey);
|
||||
ThreadUtil.runOnMain(onFailure);
|
||||
Util.runOnMain(onFailure);
|
||||
return;
|
||||
} else if (audioFileInfo.waveForm.length != BAR_COUNT) {
|
||||
Log.w(TAG, "Wave form from database does not match bar count, regenerating " + cacheKey);
|
||||
} else {
|
||||
WAVE_FORM_CACHE.put(cacheKey, audioFileInfo);
|
||||
Log.i(TAG, "Loaded wave form from DB " + cacheKey);
|
||||
ThreadUtil.runOnMain(() -> onSuccess.accept(audioFileInfo));
|
||||
Util.runOnMain(() -> onSuccess.accept(audioFileInfo));
|
||||
return;
|
||||
}
|
||||
}
|
||||
@@ -120,10 +120,10 @@ public final class AudioWaveForm {
|
||||
attachmentDatabase.writeAudioHash(dbAttachment.getAttachmentId(), fileInfo.toDatabaseProtobuf());
|
||||
|
||||
WAVE_FORM_CACHE.put(cacheKey, fileInfo);
|
||||
ThreadUtil.runOnMain(() -> onSuccess.accept(fileInfo));
|
||||
Util.runOnMain(() -> onSuccess.accept(fileInfo));
|
||||
} catch (Throwable e) {
|
||||
Log.w(TAG, "Failed to create audio wave form for " + cacheKey, e);
|
||||
ThreadUtil.runOnMain(onFailure);
|
||||
Util.runOnMain(onFailure);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@@ -18,7 +18,7 @@ public final class BackupPassphrase {
|
||||
private BackupPassphrase() {
|
||||
}
|
||||
|
||||
private static final String TAG = Log.tag(BackupPassphrase.class);
|
||||
private static final String TAG = BackupPassphrase.class.getSimpleName();
|
||||
|
||||
public static @Nullable String get(@NonNull Context context) {
|
||||
String passphrase = TextSecurePreferences.getBackupPassphrase(context);
|
||||
|
||||
@@ -5,7 +5,6 @@ import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
|
||||
import org.greenrobot.eventbus.EventBus;
|
||||
import org.signal.core.util.logging.Log;
|
||||
import org.whispersystems.libsignal.util.ByteUtil;
|
||||
|
||||
import java.security.MessageDigest;
|
||||
@@ -14,7 +13,7 @@ import java.security.NoSuchAlgorithmException;
|
||||
public abstract class FullBackupBase {
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
private static final String TAG = Log.tag(FullBackupBase.class);
|
||||
private static final String TAG = FullBackupBase.class.getSimpleName();
|
||||
|
||||
static class BackupStream {
|
||||
static @NonNull byte[] getBackupKey(@NonNull String passphrase, @Nullable byte[] salt) {
|
||||
|
||||
@@ -10,6 +10,7 @@ import androidx.annotation.Nullable;
|
||||
import androidx.annotation.RequiresApi;
|
||||
import androidx.documentfile.provider.DocumentFile;
|
||||
|
||||
import com.annimon.stream.function.Consumer;
|
||||
import com.annimon.stream.function.Predicate;
|
||||
import com.google.protobuf.ByteString;
|
||||
|
||||
@@ -25,6 +26,7 @@ import org.thoughtcrime.securesms.crypto.IdentityKeyUtil;
|
||||
import org.thoughtcrime.securesms.crypto.ModernDecryptingPartInputStream;
|
||||
import org.thoughtcrime.securesms.database.AttachmentDatabase;
|
||||
import org.thoughtcrime.securesms.database.GroupReceiptDatabase;
|
||||
import org.thoughtcrime.securesms.database.JobDatabase;
|
||||
import org.thoughtcrime.securesms.database.KeyValueDatabase;
|
||||
import org.thoughtcrime.securesms.database.MmsDatabase;
|
||||
import org.thoughtcrime.securesms.database.MmsSmsColumns;
|
||||
@@ -34,13 +36,9 @@ import org.thoughtcrime.securesms.database.SessionDatabase;
|
||||
import org.thoughtcrime.securesms.database.SignedPreKeyDatabase;
|
||||
import org.thoughtcrime.securesms.database.SmsDatabase;
|
||||
import org.thoughtcrime.securesms.database.StickerDatabase;
|
||||
import org.thoughtcrime.securesms.dependencies.ApplicationDependencies;
|
||||
import org.thoughtcrime.securesms.keyvalue.KeyValueDataSet;
|
||||
import org.thoughtcrime.securesms.keyvalue.SignalStore;
|
||||
import org.thoughtcrime.securesms.profiles.AvatarHelper;
|
||||
import org.thoughtcrime.securesms.util.SetUtil;
|
||||
import org.thoughtcrime.securesms.util.Stopwatch;
|
||||
import org.thoughtcrime.securesms.util.TextSecurePreferences;
|
||||
import org.thoughtcrime.securesms.util.Util;
|
||||
import org.whispersystems.libsignal.kdf.HKDFv3;
|
||||
import org.whispersystems.libsignal.util.ByteUtil;
|
||||
@@ -68,7 +66,8 @@ import javax.crypto.spec.SecretKeySpec;
|
||||
|
||||
public class FullBackupExporter extends FullBackupBase {
|
||||
|
||||
private static final String TAG = Log.tag(FullBackupExporter.class);
|
||||
@SuppressWarnings("unused")
|
||||
private static final String TAG = FullBackupExporter.class.getSimpleName();
|
||||
|
||||
private static final Set<String> BLACKLISTED_TABLES = SetUtil.newHashSet(
|
||||
SignedPreKeyDatabase.TABLE_NAME,
|
||||
@@ -82,12 +81,11 @@ public class FullBackupExporter extends FullBackupBase {
|
||||
@NonNull AttachmentSecret attachmentSecret,
|
||||
@NonNull SQLiteDatabase input,
|
||||
@NonNull File output,
|
||||
@NonNull String passphrase,
|
||||
@NonNull BackupCancellationSignal cancellationSignal)
|
||||
@NonNull String passphrase)
|
||||
throws IOException
|
||||
{
|
||||
try (OutputStream outputStream = new FileOutputStream(output)) {
|
||||
internalExport(context, attachmentSecret, input, outputStream, passphrase, true, cancellationSignal);
|
||||
internalExport(context, attachmentSecret, input, outputStream, passphrase);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -96,32 +94,19 @@ public class FullBackupExporter extends FullBackupBase {
|
||||
@NonNull AttachmentSecret attachmentSecret,
|
||||
@NonNull SQLiteDatabase input,
|
||||
@NonNull DocumentFile output,
|
||||
@NonNull String passphrase,
|
||||
@NonNull BackupCancellationSignal cancellationSignal)
|
||||
@NonNull String passphrase)
|
||||
throws IOException
|
||||
{
|
||||
try (OutputStream outputStream = Objects.requireNonNull(context.getContentResolver().openOutputStream(output.getUri()))) {
|
||||
internalExport(context, attachmentSecret, input, outputStream, passphrase, true, cancellationSignal);
|
||||
internalExport(context, attachmentSecret, input, outputStream, passphrase);
|
||||
}
|
||||
}
|
||||
|
||||
public static void transfer(@NonNull Context context,
|
||||
@NonNull AttachmentSecret attachmentSecret,
|
||||
@NonNull SQLiteDatabase input,
|
||||
@NonNull OutputStream outputStream,
|
||||
@NonNull String passphrase)
|
||||
throws IOException
|
||||
{
|
||||
internalExport(context, attachmentSecret, input, outputStream, passphrase, false, () -> false);
|
||||
}
|
||||
|
||||
private static void internalExport(@NonNull Context context,
|
||||
@NonNull AttachmentSecret attachmentSecret,
|
||||
@NonNull SQLiteDatabase input,
|
||||
@NonNull OutputStream fileOutputStream,
|
||||
@NonNull String passphrase,
|
||||
boolean closeOutputStream,
|
||||
@NonNull BackupCancellationSignal cancellationSignal)
|
||||
@NonNull String passphrase)
|
||||
throws IOException
|
||||
{
|
||||
BackupFrameOutputStream outputStream = new BackupFrameOutputStream(fileOutputStream, passphrase);
|
||||
@@ -129,51 +114,36 @@ public class FullBackupExporter extends FullBackupBase {
|
||||
|
||||
try {
|
||||
outputStream.writeDatabaseVersion(input.getVersion());
|
||||
count++;
|
||||
|
||||
List<String> tables = exportSchema(input, outputStream);
|
||||
count += tables.size() * 3;
|
||||
|
||||
Stopwatch stopwatch = new Stopwatch("Backup");
|
||||
|
||||
for (String table : tables) {
|
||||
throwIfCanceled(cancellationSignal);
|
||||
if (table.equals(MmsDatabase.TABLE_NAME)) {
|
||||
count = exportTable(table, input, outputStream, FullBackupExporter::isNonExpiringMmsMessage, null, count, cancellationSignal);
|
||||
count = exportTable(table, input, outputStream, FullBackupExporter::isNonExpiringMmsMessage, null, count);
|
||||
} else if (table.equals(SmsDatabase.TABLE_NAME)) {
|
||||
count = exportTable(table, input, outputStream, FullBackupExporter::isNonExpiringSmsMessage, null, count, cancellationSignal);
|
||||
count = exportTable(table, input, outputStream, FullBackupExporter::isNonExpiringSmsMessage, null, count);
|
||||
} else if (table.equals(GroupReceiptDatabase.TABLE_NAME)) {
|
||||
count = exportTable(table, input, outputStream, cursor -> isForNonExpiringMessage(input, cursor.getLong(cursor.getColumnIndexOrThrow(GroupReceiptDatabase.MMS_ID))), null, count, cancellationSignal);
|
||||
count = exportTable(table, input, outputStream, cursor -> isForNonExpiringMessage(input, cursor.getLong(cursor.getColumnIndexOrThrow(GroupReceiptDatabase.MMS_ID))), null, count);
|
||||
} else if (table.equals(AttachmentDatabase.TABLE_NAME)) {
|
||||
count = exportTable(table, input, outputStream, cursor -> isForNonExpiringMessage(input, cursor.getLong(cursor.getColumnIndexOrThrow(AttachmentDatabase.MMS_ID))), (cursor, innerCount) -> exportAttachment(attachmentSecret, cursor, outputStream, innerCount), count, cancellationSignal);
|
||||
count = exportTable(table, input, outputStream, cursor -> isForNonExpiringMessage(input, cursor.getLong(cursor.getColumnIndexOrThrow(AttachmentDatabase.MMS_ID))), cursor -> exportAttachment(attachmentSecret, cursor, outputStream), count);
|
||||
} else if (table.equals(StickerDatabase.TABLE_NAME)) {
|
||||
count = exportTable(table, input, outputStream, cursor -> true, (cursor, innerCount) -> exportSticker(attachmentSecret, cursor, outputStream, innerCount), count, cancellationSignal);
|
||||
count = exportTable(table, input, outputStream, cursor -> true, cursor -> exportSticker(attachmentSecret, cursor, outputStream), count);
|
||||
} else if (!BLACKLISTED_TABLES.contains(table) && !table.startsWith("sqlite_")) {
|
||||
count = exportTable(table, input, outputStream, null, null, count, cancellationSignal);
|
||||
count = exportTable(table, input, outputStream, null, null, count);
|
||||
}
|
||||
stopwatch.split("table::" + table);
|
||||
}
|
||||
|
||||
for (BackupProtos.SharedPreference preference : IdentityKeyUtil.getBackupRecord(context)) {
|
||||
throwIfCanceled(cancellationSignal);
|
||||
EventBus.getDefault().post(new BackupEvent(BackupEvent.Type.PROGRESS, ++count));
|
||||
outputStream.write(preference);
|
||||
}
|
||||
|
||||
for (BackupProtos.SharedPreference preference : TextSecurePreferences.getPreferencesToSaveToBackup(context)) {
|
||||
throwIfCanceled(cancellationSignal);
|
||||
EventBus.getDefault().post(new BackupEvent(BackupEvent.Type.PROGRESS, ++count));
|
||||
outputStream.write(preference);
|
||||
}
|
||||
|
||||
stopwatch.split("prefs");
|
||||
|
||||
count = exportKeyValues(outputStream, SignalStore.getKeysToIncludeInBackup(), count, cancellationSignal);
|
||||
|
||||
stopwatch.split("key_values");
|
||||
|
||||
for (AvatarHelper.Avatar avatar : AvatarHelper.getAvatars(context)) {
|
||||
throwIfCanceled(cancellationSignal);
|
||||
if (avatar != null) {
|
||||
EventBus.getDefault().post(new BackupEvent(BackupEvent.Type.PROGRESS, ++count));
|
||||
outputStream.write(avatar.getFilename(), avatar.getInputStream(), avatar.getLength());
|
||||
@@ -185,19 +155,11 @@ public class FullBackupExporter extends FullBackupBase {
|
||||
|
||||
outputStream.writeEnd();
|
||||
} finally {
|
||||
if (closeOutputStream) {
|
||||
outputStream.close();
|
||||
}
|
||||
outputStream.close();
|
||||
EventBus.getDefault().post(new BackupEvent(BackupEvent.Type.FINISHED, ++count));
|
||||
}
|
||||
}
|
||||
|
||||
private static void throwIfCanceled(@NonNull BackupCancellationSignal cancellationSignal) throws BackupCanceledException {
|
||||
if (cancellationSignal.isCanceled()) {
|
||||
throw new BackupCanceledException();
|
||||
}
|
||||
}
|
||||
|
||||
private static List<String> exportSchema(@NonNull SQLiteDatabase input, @NonNull BackupFrameOutputStream outputStream)
|
||||
throws IOException
|
||||
{
|
||||
@@ -228,20 +190,19 @@ public class FullBackupExporter extends FullBackupBase {
|
||||
return tables;
|
||||
}
|
||||
|
||||
private static int exportTable(@NonNull String table,
|
||||
@NonNull SQLiteDatabase input,
|
||||
@NonNull BackupFrameOutputStream outputStream,
|
||||
@Nullable Predicate<Cursor> predicate,
|
||||
@Nullable PostProcessor postProcess,
|
||||
int count,
|
||||
@NonNull BackupCancellationSignal cancellationSignal)
|
||||
private static int exportTable(@NonNull String table,
|
||||
@NonNull SQLiteDatabase input,
|
||||
@NonNull BackupFrameOutputStream outputStream,
|
||||
@Nullable Predicate<Cursor> predicate,
|
||||
@Nullable Consumer<Cursor> postProcess,
|
||||
int count)
|
||||
throws IOException
|
||||
{
|
||||
String template = "INSERT INTO " + table + " VALUES ";
|
||||
|
||||
try (Cursor cursor = input.rawQuery("SELECT * FROM " + table, null)) {
|
||||
while (cursor != null && cursor.moveToNext()) {
|
||||
throwIfCanceled(cancellationSignal);
|
||||
EventBus.getDefault().post(new BackupEvent(BackupEvent.Type.PROGRESS, ++count));
|
||||
|
||||
if (predicate == null || predicate.test(cursor)) {
|
||||
StringBuilder statement = new StringBuilder(template);
|
||||
@@ -273,12 +234,9 @@ public class FullBackupExporter extends FullBackupBase {
|
||||
|
||||
statement.append(')');
|
||||
|
||||
EventBus.getDefault().post(new BackupEvent(BackupEvent.Type.PROGRESS, ++count));
|
||||
outputStream.write(statementBuilder.setStatement(statement.toString()).build());
|
||||
|
||||
if (postProcess != null) {
|
||||
count = postProcess.postProcess(cursor, count);
|
||||
}
|
||||
if (postProcess != null) postProcess.accept(cursor);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -286,7 +244,7 @@ public class FullBackupExporter extends FullBackupBase {
|
||||
return count;
|
||||
}
|
||||
|
||||
private static int exportAttachment(@NonNull AttachmentSecret attachmentSecret, @NonNull Cursor cursor, @NonNull BackupFrameOutputStream outputStream, int count) {
|
||||
private static void exportAttachment(@NonNull AttachmentSecret attachmentSecret, @NonNull Cursor cursor, @NonNull BackupFrameOutputStream outputStream) {
|
||||
try {
|
||||
long rowId = cursor.getLong(cursor.getColumnIndexOrThrow(AttachmentDatabase.ROW_ID));
|
||||
long uniqueId = cursor.getLong(cursor.getColumnIndexOrThrow(AttachmentDatabase.UNIQUE_ID));
|
||||
@@ -311,17 +269,14 @@ public class FullBackupExporter extends FullBackupBase {
|
||||
if (random != null && random.length == 32) inputStream = ModernDecryptingPartInputStream.createFor(attachmentSecret, random, new File(data), 0);
|
||||
else inputStream = ClassicDecryptingPartInputStream.createFor(attachmentSecret, new File(data));
|
||||
|
||||
EventBus.getDefault().post(new BackupEvent(BackupEvent.Type.PROGRESS, ++count));
|
||||
outputStream.write(new AttachmentId(rowId, uniqueId), inputStream, size);
|
||||
}
|
||||
} catch (IOException e) {
|
||||
Log.w(TAG, e);
|
||||
}
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
private static int exportSticker(@NonNull AttachmentSecret attachmentSecret, @NonNull Cursor cursor, @NonNull BackupFrameOutputStream outputStream, int count) {
|
||||
private static void exportSticker(@NonNull AttachmentSecret attachmentSecret, @NonNull Cursor cursor, @NonNull BackupFrameOutputStream outputStream) {
|
||||
try {
|
||||
long rowId = cursor.getLong(cursor.getColumnIndexOrThrow(StickerDatabase._ID));
|
||||
long size = cursor.getLong(cursor.getColumnIndexOrThrow(StickerDatabase.FILE_LENGTH));
|
||||
@@ -330,15 +285,12 @@ public class FullBackupExporter extends FullBackupBase {
|
||||
byte[] random = cursor.getBlob(cursor.getColumnIndexOrThrow(StickerDatabase.FILE_RANDOM));
|
||||
|
||||
if (!TextUtils.isEmpty(data) && size > 0) {
|
||||
EventBus.getDefault().post(new BackupEvent(BackupEvent.Type.PROGRESS, ++count));
|
||||
InputStream inputStream = ModernDecryptingPartInputStream.createFor(attachmentSecret, random, new File(data), 0);
|
||||
outputStream.writeSticker(rowId, inputStream, size);
|
||||
}
|
||||
} catch (IOException e) {
|
||||
Log.w(TAG, e);
|
||||
}
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
private static long calculateVeryOldStreamLength(@NonNull AttachmentSecret attachmentSecret, @Nullable byte[] random, @NonNull String data) throws IOException {
|
||||
@@ -358,46 +310,6 @@ public class FullBackupExporter extends FullBackupBase {
|
||||
return result;
|
||||
}
|
||||
|
||||
private static int exportKeyValues(@NonNull BackupFrameOutputStream outputStream,
|
||||
@NonNull List<String> keysToIncludeInBackup,
|
||||
int count,
|
||||
BackupCancellationSignal cancellationSignal) throws IOException
|
||||
{
|
||||
KeyValueDataSet dataSet = KeyValueDatabase.getInstance(ApplicationDependencies.getApplication())
|
||||
.getDataSet();
|
||||
|
||||
for (String key : keysToIncludeInBackup) {
|
||||
throwIfCanceled(cancellationSignal);
|
||||
if (!dataSet.containsKey(key)) {
|
||||
continue;
|
||||
}
|
||||
BackupProtos.KeyValue.Builder builder = BackupProtos.KeyValue.newBuilder()
|
||||
.setKey(key);
|
||||
|
||||
Class<?> type = dataSet.getType(key);
|
||||
if (type == byte[].class) {
|
||||
builder.setBlobValue(ByteString.copyFrom(dataSet.getBlob(key, null)));
|
||||
} else if (type == Boolean.class) {
|
||||
builder.setBooleanValue(dataSet.getBoolean(key, false));
|
||||
} else if (type == Float.class) {
|
||||
builder.setFloatValue(dataSet.getFloat(key, 0));
|
||||
} else if (type == Integer.class) {
|
||||
builder.setIntegerValue(dataSet.getInteger(key, 0));
|
||||
} else if (type == Long.class) {
|
||||
builder.setLongValue(dataSet.getLong(key, 0));
|
||||
} else if (type == String.class) {
|
||||
builder.setStringValue(dataSet.getString(key, null));
|
||||
} else {
|
||||
throw new AssertionError("Unknown type: " + type);
|
||||
}
|
||||
|
||||
EventBus.getDefault().post(new BackupEvent(BackupEvent.Type.PROGRESS, ++count));
|
||||
outputStream.write(builder.build());
|
||||
}
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
private static boolean isNonExpiringMmsMessage(@NonNull Cursor cursor) {
|
||||
return cursor.getInt(cursor.getColumnIndexOrThrow(MmsSmsColumns.EXPIRES_IN)) <= 0 &&
|
||||
cursor.getInt(cursor.getColumnIndexOrThrow(MmsDatabase.VIEW_ONCE)) <= 0;
|
||||
@@ -469,10 +381,6 @@ public class FullBackupExporter extends FullBackupBase {
|
||||
write(outputStream, BackupProtos.BackupFrame.newBuilder().setPreference(preference).build());
|
||||
}
|
||||
|
||||
public void write(BackupProtos.KeyValue keyValue) throws IOException {
|
||||
write(outputStream, BackupProtos.BackupFrame.newBuilder().setKeyValue(keyValue).build());
|
||||
}
|
||||
|
||||
public void write(BackupProtos.SqlStatement statement) throws IOException {
|
||||
write(outputStream, BackupProtos.BackupFrame.newBuilder().setStatement(statement).build());
|
||||
}
|
||||
@@ -587,14 +495,4 @@ public class FullBackupExporter extends FullBackupBase {
|
||||
outputStream.close();
|
||||
}
|
||||
}
|
||||
|
||||
public interface PostProcessor {
|
||||
int postProcess(@NonNull Cursor cursor, int count);
|
||||
}
|
||||
|
||||
public interface BackupCancellationSignal {
|
||||
boolean isCanceled();
|
||||
}
|
||||
|
||||
public static final class BackupCanceledException extends IOException { }
|
||||
}
|
||||
|
||||
@@ -26,11 +26,8 @@ import org.thoughtcrime.securesms.backup.BackupProtos.Sticker;
|
||||
import org.thoughtcrime.securesms.crypto.AttachmentSecret;
|
||||
import org.thoughtcrime.securesms.crypto.ModernEncryptingPartOutputStream;
|
||||
import org.thoughtcrime.securesms.database.AttachmentDatabase;
|
||||
import org.thoughtcrime.securesms.database.KeyValueDatabase;
|
||||
import org.thoughtcrime.securesms.database.SearchDatabase;
|
||||
import org.thoughtcrime.securesms.database.StickerDatabase;
|
||||
import org.thoughtcrime.securesms.dependencies.ApplicationDependencies;
|
||||
import org.thoughtcrime.securesms.keyvalue.KeyValueDataSet;
|
||||
import org.thoughtcrime.securesms.profiles.AvatarHelper;
|
||||
import org.thoughtcrime.securesms.recipients.RecipientId;
|
||||
import org.thoughtcrime.securesms.util.BackupUtil;
|
||||
@@ -48,8 +45,6 @@ import java.security.InvalidAlgorithmParameterException;
|
||||
import java.security.InvalidKeyException;
|
||||
import java.security.MessageDigest;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import java.util.Collections;
|
||||
import java.util.HashSet;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
@@ -65,37 +60,25 @@ import javax.crypto.spec.SecretKeySpec;
|
||||
public class FullBackupImporter extends FullBackupBase {
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
private static final String TAG = Log.tag(FullBackupImporter.class);
|
||||
private static final String TAG = FullBackupImporter.class.getSimpleName();
|
||||
|
||||
public static void importFile(@NonNull Context context, @NonNull AttachmentSecret attachmentSecret,
|
||||
@NonNull SQLiteDatabase db, @NonNull Uri uri, @NonNull String passphrase)
|
||||
throws IOException
|
||||
{
|
||||
try (InputStream is = getInputStream(context, uri)) {
|
||||
importFile(context, attachmentSecret, db, is, passphrase);
|
||||
}
|
||||
}
|
||||
|
||||
public static void importFile(@NonNull Context context, @NonNull AttachmentSecret attachmentSecret,
|
||||
@NonNull SQLiteDatabase db, @NonNull InputStream is, @NonNull String passphrase)
|
||||
throws IOException
|
||||
{
|
||||
int count = 0;
|
||||
|
||||
SQLiteDatabase keyValueDatabase = KeyValueDatabase.getInstance(ApplicationDependencies.getApplication()).getSqlCipherDatabase();
|
||||
try {
|
||||
try (InputStream is = getInputStream(context, uri)) {
|
||||
BackupRecordInputStream inputStream = new BackupRecordInputStream(is, passphrase);
|
||||
|
||||
db.beginTransaction();
|
||||
keyValueDatabase.beginTransaction();
|
||||
|
||||
dropAllTables(db);
|
||||
|
||||
BackupFrame frame;
|
||||
|
||||
while (!(frame = inputStream.readFrame()).getEnd()) {
|
||||
if (count % 100 == 0) EventBus.getDefault().post(new BackupEvent(BackupEvent.Type.PROGRESS, count));
|
||||
count++;
|
||||
if (count++ % 100 == 0) EventBus.getDefault().post(new BackupEvent(BackupEvent.Type.PROGRESS, count));
|
||||
|
||||
if (frame.hasVersion()) processVersion(db, frame.getVersion());
|
||||
else if (frame.hasStatement()) processStatement(db, frame.getStatement());
|
||||
@@ -103,22 +86,18 @@ public class FullBackupImporter extends FullBackupBase {
|
||||
else if (frame.hasAttachment()) processAttachment(context, attachmentSecret, db, frame.getAttachment(), inputStream);
|
||||
else if (frame.hasSticker()) processSticker(context, attachmentSecret, db, frame.getSticker(), inputStream);
|
||||
else if (frame.hasAvatar()) processAvatar(context, db, frame.getAvatar(), inputStream);
|
||||
else if (frame.hasKeyValue()) processKeyValue(frame.getKeyValue());
|
||||
else count--;
|
||||
}
|
||||
|
||||
db.setTransactionSuccessful();
|
||||
keyValueDatabase.setTransactionSuccessful();
|
||||
} finally {
|
||||
db.endTransaction();
|
||||
keyValueDatabase.endTransaction();
|
||||
}
|
||||
|
||||
EventBus.getDefault().post(new BackupEvent(BackupEvent.Type.FINISHED, count));
|
||||
}
|
||||
|
||||
private static @NonNull InputStream getInputStream(@NonNull Context context, @NonNull Uri uri) throws IOException{
|
||||
if (BackupUtil.isUserSelectionRequired(context) || uri.getScheme().equals("content")) {
|
||||
if (BackupUtil.isUserSelectionRequired(context)) {
|
||||
return Objects.requireNonNull(context.getContentResolver().openInputStream(uri));
|
||||
} else {
|
||||
return new FileInputStream(new File(Objects.requireNonNull(uri.getPath())));
|
||||
@@ -222,40 +201,10 @@ public class FullBackupImporter extends FullBackupBase {
|
||||
}
|
||||
}
|
||||
|
||||
private static void processKeyValue(BackupProtos.KeyValue keyValue) {
|
||||
KeyValueDataSet dataSet = new KeyValueDataSet();
|
||||
|
||||
if (keyValue.hasBlobValue()) {
|
||||
dataSet.putBlob(keyValue.getKey(), keyValue.getBlobValue().toByteArray());
|
||||
} else if (keyValue.hasBooleanValue()) {
|
||||
dataSet.putBoolean(keyValue.getKey(), keyValue.getBooleanValue());
|
||||
} else if (keyValue.hasFloatValue()) {
|
||||
dataSet.putFloat(keyValue.getKey(), keyValue.getFloatValue());
|
||||
} else if (keyValue.hasIntegerValue()) {
|
||||
dataSet.putInteger(keyValue.getKey(), keyValue.getIntegerValue());
|
||||
} else if (keyValue.hasLongValue()) {
|
||||
dataSet.putLong(keyValue.getKey(), keyValue.getLongValue());
|
||||
} else if (keyValue.hasStringValue()) {
|
||||
dataSet.putString(keyValue.getKey(), keyValue.getStringValue());
|
||||
} else {
|
||||
Log.i(TAG, "Unknown KeyValue backup value, skipping");
|
||||
return;
|
||||
}
|
||||
|
||||
KeyValueDatabase.getInstance(ApplicationDependencies.getApplication()).writeDataSet(dataSet, Collections.emptyList());
|
||||
}
|
||||
|
||||
@SuppressLint("ApplySharedPref")
|
||||
private static void processPreference(@NonNull Context context, SharedPreference preference) {
|
||||
SharedPreferences preferences = context.getSharedPreferences(preference.getFile(), 0);
|
||||
|
||||
if (preference.hasValue()) {
|
||||
preferences.edit().putString(preference.getKey(), preference.getValue()).commit();
|
||||
} else if (preference.hasBooleanValue()) {
|
||||
preferences.edit().putBoolean(preference.getKey(), preference.getBooleanValue()).commit();
|
||||
} else if (preference.hasIsStringSetValue() && preference.getIsStringSetValue()) {
|
||||
preferences.edit().putStringSet(preference.getKey(), new HashSet<>(preference.getStringSetValueList())).commit();
|
||||
}
|
||||
preferences.edit().putString(preference.getKey(), preference.getValue()).commit();
|
||||
}
|
||||
|
||||
private static void dropAllTables(@NonNull SQLiteDatabase db) {
|
||||
|
||||
@@ -9,12 +9,11 @@ import android.view.View;
|
||||
import android.widget.ImageView;
|
||||
import android.widget.LinearLayout;
|
||||
|
||||
import org.signal.core.util.logging.Log;
|
||||
import org.thoughtcrime.securesms.R;
|
||||
|
||||
public class AlertView extends LinearLayout {
|
||||
|
||||
private static final String TAG = Log.tag(AlertView.class);
|
||||
private static final String TAG = AlertView.class.getSimpleName();
|
||||
|
||||
private ImageView approvalIndicator;
|
||||
private ImageView failedIndicator;
|
||||
|
||||
@@ -29,7 +29,6 @@ import com.pnikosis.materialishprogress.ProgressWheel;
|
||||
import org.greenrobot.eventbus.EventBus;
|
||||
import org.greenrobot.eventbus.Subscribe;
|
||||
import org.greenrobot.eventbus.ThreadMode;
|
||||
import org.signal.core.util.logging.Log;
|
||||
import org.thoughtcrime.securesms.R;
|
||||
import org.thoughtcrime.securesms.audio.AudioWaveForm;
|
||||
import org.thoughtcrime.securesms.components.voice.VoiceNotePlaybackState;
|
||||
@@ -43,7 +42,7 @@ import java.util.concurrent.TimeUnit;
|
||||
|
||||
public final class AudioView extends FrameLayout {
|
||||
|
||||
private static final String TAG = Log.tag(AudioView.class);
|
||||
private static final String TAG = AudioView.class.getSimpleName();
|
||||
|
||||
private static final int FORWARDS = 1;
|
||||
private static final int REVERSE = -1;
|
||||
|
||||
@@ -2,33 +2,25 @@ package org.thoughtcrime.securesms.components;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.res.TypedArray;
|
||||
import android.graphics.Bitmap;
|
||||
import android.graphics.Canvas;
|
||||
import android.graphics.Color;
|
||||
import android.graphics.Paint;
|
||||
import android.graphics.drawable.Drawable;
|
||||
import android.util.AttributeSet;
|
||||
|
||||
import androidx.annotation.DrawableRes;
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.appcompat.widget.AppCompatImageView;
|
||||
import androidx.fragment.app.FragmentActivity;
|
||||
|
||||
import com.bumptech.glide.load.MultiTransformation;
|
||||
import com.bumptech.glide.load.Transformation;
|
||||
import com.bumptech.glide.load.engine.DiskCacheStrategy;
|
||||
import com.bumptech.glide.load.resource.bitmap.CircleCrop;
|
||||
import com.bumptech.glide.load.resource.bitmap.DownsampleStrategy;
|
||||
|
||||
import org.signal.core.util.logging.Log;
|
||||
import org.thoughtcrime.securesms.R;
|
||||
import org.thoughtcrime.securesms.color.MaterialColor;
|
||||
import org.thoughtcrime.securesms.contacts.avatars.ContactColors;
|
||||
import org.thoughtcrime.securesms.contacts.avatars.ContactPhoto;
|
||||
import org.thoughtcrime.securesms.contacts.avatars.ProfileContactPhoto;
|
||||
import org.thoughtcrime.securesms.contacts.avatars.ResourceContactPhoto;
|
||||
import org.thoughtcrime.securesms.dependencies.ApplicationDependencies;
|
||||
import org.thoughtcrime.securesms.groups.ui.managegroup.ManageGroupActivity;
|
||||
import org.thoughtcrime.securesms.mms.GlideApp;
|
||||
import org.thoughtcrime.securesms.mms.GlideRequests;
|
||||
@@ -36,12 +28,9 @@ import org.thoughtcrime.securesms.recipients.Recipient;
|
||||
import org.thoughtcrime.securesms.recipients.ui.bottomsheet.RecipientBottomSheetDialogFragment;
|
||||
import org.thoughtcrime.securesms.recipients.ui.managerecipient.ManageRecipientActivity;
|
||||
import org.thoughtcrime.securesms.util.AvatarUtil;
|
||||
import org.thoughtcrime.securesms.util.BlurTransformation;
|
||||
import org.thoughtcrime.securesms.util.ThemeUtil;
|
||||
import org.thoughtcrime.securesms.util.Util;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
|
||||
public final class AvatarImageView extends AppCompatImageView {
|
||||
@@ -50,7 +39,7 @@ public final class AvatarImageView extends AppCompatImageView {
|
||||
private static final int SIZE_SMALL = 2;
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
private static final String TAG = Log.tag(AvatarImageView.class);
|
||||
private static final String TAG = AvatarImageView.class.getSimpleName();
|
||||
|
||||
private static final Paint LIGHT_THEME_OUTLINE_PAINT = new Paint();
|
||||
private static final Paint DARK_THEME_OUTLINE_PAINT = new Paint();
|
||||
@@ -72,7 +61,6 @@ public final class AvatarImageView extends AppCompatImageView {
|
||||
private Paint outlinePaint;
|
||||
private OnClickListener listener;
|
||||
private Recipient.FallbackPhotoProvider fallbackPhotoProvider;
|
||||
private boolean blurred;
|
||||
|
||||
private @Nullable RecipientContactPhoto recipientContactPhoto;
|
||||
private @NonNull Drawable unknownRecipientDrawable;
|
||||
@@ -100,16 +88,15 @@ public final class AvatarImageView extends AppCompatImageView {
|
||||
outlinePaint = ThemeUtil.isDarkTheme(getContext()) ? DARK_THEME_OUTLINE_PAINT : LIGHT_THEME_OUTLINE_PAINT;
|
||||
|
||||
unknownRecipientDrawable = new ResourceContactPhoto(R.drawable.ic_profile_outline_40, R.drawable.ic_profile_outline_20).asDrawable(getContext(), ContactColors.UNKNOWN_COLOR.toConversationColor(getContext()), inverted);
|
||||
blurred = false;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onDraw(Canvas canvas) {
|
||||
super.onDraw(canvas);
|
||||
|
||||
float width = getWidth() - getPaddingRight() - getPaddingLeft();
|
||||
float width = getWidth() - getPaddingRight() - getPaddingLeft();
|
||||
float height = getHeight() - getPaddingBottom() - getPaddingTop();
|
||||
float cx = width / 2f;
|
||||
float cx = width / 2f;
|
||||
float cy = height / 2f;
|
||||
float radius = Math.min(cx, cy) - (outlinePaint.getStrokeWidth() / 2f);
|
||||
|
||||
@@ -131,18 +118,11 @@ public final class AvatarImageView extends AppCompatImageView {
|
||||
* Shows self as the actual profile picture.
|
||||
*/
|
||||
public void setRecipient(@NonNull Recipient recipient) {
|
||||
setRecipient(recipient, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Shows self as the actual profile picture.
|
||||
*/
|
||||
public void setRecipient(@NonNull Recipient recipient, boolean quickContactEnabled) {
|
||||
if (recipient.isSelf()) {
|
||||
setAvatar(GlideApp.with(this), null, quickContactEnabled);
|
||||
setAvatar(GlideApp.with(this), null, false);
|
||||
AvatarUtil.loadIconIntoImageView(recipient, this);
|
||||
} else {
|
||||
setAvatar(GlideApp.with(this), recipient, quickContactEnabled);
|
||||
setAvatar(GlideApp.with(this), recipient, false);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -171,30 +151,20 @@ public final class AvatarImageView extends AppCompatImageView {
|
||||
Recipient.self().getProfileAvatar()))
|
||||
: new RecipientContactPhoto(recipient);
|
||||
|
||||
boolean shouldBlur = recipient.shouldBlurAvatar();
|
||||
|
||||
if (!photo.equals(recipientContactPhoto) || shouldBlur != blurred) {
|
||||
if (!photo.equals(recipientContactPhoto)) {
|
||||
requestManager.clear(this);
|
||||
recipientContactPhoto = photo;
|
||||
|
||||
Drawable fallbackContactPhotoDrawable = size == SIZE_SMALL ? photo.recipient.getSmallFallbackContactPhotoDrawable(getContext(), inverted, fallbackPhotoProvider)
|
||||
: photo.recipient.getFallbackContactPhotoDrawable(getContext(), inverted, fallbackPhotoProvider);
|
||||
Drawable fallbackContactPhotoDrawable = size == SIZE_SMALL
|
||||
? photo.recipient.getSmallFallbackContactPhotoDrawable(getContext(), inverted, fallbackPhotoProvider)
|
||||
: photo.recipient.getFallbackContactPhotoDrawable(getContext(), inverted, fallbackPhotoProvider);
|
||||
|
||||
if (photo.contactPhoto != null) {
|
||||
|
||||
List<Transformation<Bitmap>> transforms = new ArrayList<>();
|
||||
if (shouldBlur) {
|
||||
transforms.add(new BlurTransformation(ApplicationDependencies.getApplication(), 0.25f, BlurTransformation.MAX_RADIUS));
|
||||
}
|
||||
transforms.add(new CircleCrop());
|
||||
blurred = shouldBlur;
|
||||
|
||||
requestManager.load(photo.contactPhoto)
|
||||
.fallback(fallbackContactPhotoDrawable)
|
||||
.error(fallbackContactPhotoDrawable)
|
||||
.diskCacheStrategy(DiskCacheStrategy.ALL)
|
||||
.downsample(DownsampleStrategy.CENTER_INSIDE)
|
||||
.transform(new MultiTransformation<>(transforms))
|
||||
.circleCrop()
|
||||
.into(this);
|
||||
} else {
|
||||
setImageDrawable(fallbackContactPhotoDrawable);
|
||||
@@ -234,7 +204,8 @@ public final class AvatarImageView extends AppCompatImageView {
|
||||
}
|
||||
});
|
||||
} else {
|
||||
disableQuickContact();
|
||||
super.setOnClickListener(listener);
|
||||
setClickable(listener != null);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -255,16 +226,6 @@ public final class AvatarImageView extends AppCompatImageView {
|
||||
.into(this);
|
||||
}
|
||||
|
||||
public void setNonAvatarImageResource(@DrawableRes int imageResource) {
|
||||
recipientContactPhoto = null;
|
||||
setImageResource(imageResource);
|
||||
}
|
||||
|
||||
public void disableQuickContact() {
|
||||
super.setOnClickListener(listener);
|
||||
setClickable(listener != null);
|
||||
}
|
||||
|
||||
private static class RecipientContactPhoto {
|
||||
|
||||
private final @NonNull Recipient recipient;
|
||||
|
||||
@@ -40,7 +40,6 @@ import org.thoughtcrime.securesms.util.StringUtil;
|
||||
import org.thoughtcrime.securesms.util.TextSecurePreferences;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
|
||||
import static org.thoughtcrime.securesms.database.MentionUtil.MENTION_STARTER;
|
||||
|
||||
@@ -85,13 +84,13 @@ public class ComposeText extends EmojiEditText {
|
||||
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
|
||||
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
|
||||
|
||||
if (getLayout() != null && !TextUtils.isEmpty(hint)) {
|
||||
if (!TextUtils.isEmpty(hint)) {
|
||||
if (!TextUtils.isEmpty(subHint)) {
|
||||
setHintWithChecks(new SpannableStringBuilder().append(ellipsizeToWidth(hint))
|
||||
.append("\n")
|
||||
.append(ellipsizeToWidth(subHint)));
|
||||
setHint(new SpannableStringBuilder().append(ellipsizeToWidth(hint))
|
||||
.append("\n")
|
||||
.append(ellipsizeToWidth(subHint)));
|
||||
} else {
|
||||
setHintWithChecks(ellipsizeToWidth(hint));
|
||||
setHint(ellipsizeToWidth(hint));
|
||||
}
|
||||
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
|
||||
}
|
||||
@@ -161,14 +160,14 @@ public class ComposeText extends EmojiEditText {
|
||||
}
|
||||
|
||||
if (this.subHint != null) {
|
||||
setHintWithChecks(new SpannableStringBuilder().append(ellipsizeToWidth(this.hint))
|
||||
.append("\n")
|
||||
.append(ellipsizeToWidth(this.subHint)));
|
||||
super.setHint(new SpannableStringBuilder().append(ellipsizeToWidth(this.hint))
|
||||
.append("\n")
|
||||
.append(ellipsizeToWidth(this.subHint)));
|
||||
} else {
|
||||
setHintWithChecks(ellipsizeToWidth(this.hint));
|
||||
super.setHint(ellipsizeToWidth(this.hint));
|
||||
}
|
||||
|
||||
setHintWithChecks(hint);
|
||||
super.setHint(hint);
|
||||
}
|
||||
|
||||
public void appendInvite(String invite) {
|
||||
@@ -265,14 +264,6 @@ public class ComposeText extends EmojiEditText {
|
||||
addTextChangedListener(mentionValidatorWatcher);
|
||||
}
|
||||
|
||||
private void setHintWithChecks(@Nullable CharSequence newHint) {
|
||||
if (getLayout() == null || Objects.equals(getHint(), newHint)) {
|
||||
return;
|
||||
}
|
||||
|
||||
setHint(newHint);
|
||||
}
|
||||
|
||||
private boolean changeSelectionForPartialMentions(@NonNull Spanned spanned, int selectionStart, int selectionEnd) {
|
||||
Annotation[] annotations = spanned.getSpans(0, spanned.length(), Annotation.class);
|
||||
for (Annotation annotation : annotations) {
|
||||
@@ -374,7 +365,7 @@ public class ComposeText extends EmojiEditText {
|
||||
|
||||
private static class CommitContentListener implements InputConnectionCompat.OnCommitContentListener {
|
||||
|
||||
private static final String TAG = Log.tag(CommitContentListener.class);
|
||||
private static final String TAG = CommitContentListener.class.getSimpleName();
|
||||
|
||||
private final InputPanel.MediaListener mediaListener;
|
||||
|
||||
|
||||
@@ -26,7 +26,6 @@ import org.thoughtcrime.securesms.R;
|
||||
import org.thoughtcrime.securesms.database.DatabaseFactory;
|
||||
import org.thoughtcrime.securesms.database.model.MessageRecord;
|
||||
import org.thoughtcrime.securesms.database.model.MmsMessageRecord;
|
||||
import org.thoughtcrime.securesms.dependencies.ApplicationDependencies;
|
||||
import org.thoughtcrime.securesms.permissions.Permissions;
|
||||
import org.thoughtcrime.securesms.service.ExpiringMessageManager;
|
||||
import org.thoughtcrime.securesms.util.DateUtils;
|
||||
@@ -99,7 +98,7 @@ public class ConversationItemFooter extends LinearLayout {
|
||||
presentTimer(messageRecord);
|
||||
presentInsecureIndicator(messageRecord);
|
||||
presentDeliveryStatus(messageRecord);
|
||||
presentAudioDuration(messageRecord);
|
||||
hideAudioDurationViews();
|
||||
}
|
||||
|
||||
public void setAudioDuration(long totalDurationMillis, long currentPostionMillis) {
|
||||
@@ -198,11 +197,11 @@ public class ConversationItemFooter extends LinearLayout {
|
||||
this.timerView.startAnimation();
|
||||
|
||||
if (messageRecord.getExpireStarted() + messageRecord.getExpiresIn() <= System.currentTimeMillis()) {
|
||||
ApplicationDependencies.getExpiringMessageManager().checkSchedule();
|
||||
ApplicationContext.getInstance(getContext()).getExpiringMessageManager().checkSchedule();
|
||||
}
|
||||
} else if (!messageRecord.isOutgoing() && !messageRecord.isMediaPending()) {
|
||||
SignalExecutors.BOUNDED.execute(() -> {
|
||||
ExpiringMessageManager expirationManager = ApplicationDependencies.getExpiringMessageManager();
|
||||
ExpiringMessageManager expirationManager = ApplicationContext.getInstance(getContext()).getExpiringMessageManager();
|
||||
long id = messageRecord.getId();
|
||||
boolean mms = messageRecord.isMms();
|
||||
|
||||
@@ -259,12 +258,6 @@ public class ConversationItemFooter extends LinearLayout {
|
||||
moveAudioViewsForIncoming();
|
||||
}
|
||||
showAudioDurationViews();
|
||||
|
||||
if (messageRecord.getViewedReceiptCount() > 0) {
|
||||
revealDot.setProgress(1f);
|
||||
} else {
|
||||
revealDot.setProgress(0f);
|
||||
}
|
||||
} else {
|
||||
hideAudioDurationViews();
|
||||
}
|
||||
@@ -282,8 +275,8 @@ public class ConversationItemFooter extends LinearLayout {
|
||||
addView(audioDuration, 0);
|
||||
|
||||
int padStart = ViewUtil.dpToPx(60);
|
||||
int padLeft = ViewUtil.isLtr(this) ? padStart : 0;
|
||||
int padRight = ViewUtil.isRtl(this) ? padStart : 0;
|
||||
int padLeft = getLayoutDirection() == LAYOUT_DIRECTION_LTR ? padStart : 0;
|
||||
int padRight = getLayoutDirection() == LAYOUT_DIRECTION_RTL ? padStart : 0;
|
||||
|
||||
audioDuration.setPadding(padLeft, 0, padRight, 0);
|
||||
}
|
||||
@@ -301,7 +294,7 @@ public class ConversationItemFooter extends LinearLayout {
|
||||
|
||||
private void showAudioDurationViews() {
|
||||
audioSpace.setVisibility(View.VISIBLE);
|
||||
audioDuration.setVisibility(View.GONE);
|
||||
audioDuration.setVisibility(View.VISIBLE);
|
||||
|
||||
if (FeatureFlags.viewedReceipts()) {
|
||||
revealDot.setVisibility(View.VISIBLE);
|
||||
|
||||
@@ -19,7 +19,6 @@ import org.thoughtcrime.securesms.mms.GlideRequests;
|
||||
import org.thoughtcrime.securesms.mms.Slide;
|
||||
import org.thoughtcrime.securesms.mms.SlideClickListener;
|
||||
import org.thoughtcrime.securesms.mms.SlidesClickedListener;
|
||||
import org.thoughtcrime.securesms.util.ViewUtil;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@@ -33,9 +32,6 @@ public class ConversationItemThumbnail extends FrameLayout {
|
||||
private Outliner outliner;
|
||||
private Outliner pulseOutliner;
|
||||
private boolean borderless;
|
||||
private int[] normalBounds;
|
||||
private int[] gifBounds;
|
||||
private int minimumThumbnailWidth;
|
||||
|
||||
public ConversationItemThumbnail(Context context) {
|
||||
super(context);
|
||||
@@ -64,30 +60,14 @@ public class ConversationItemThumbnail extends FrameLayout {
|
||||
|
||||
outliner.setColor(ContextCompat.getColor(getContext(), R.color.signal_inverse_transparent_20));
|
||||
|
||||
int gifWidth = ViewUtil.dpToPx(260);
|
||||
if (attrs != null) {
|
||||
TypedArray typedArray = getContext().getTheme().obtainStyledAttributes(attrs, R.styleable.ConversationItemThumbnail, 0, 0);
|
||||
normalBounds = new int[]{
|
||||
typedArray.getDimensionPixelSize(R.styleable.ConversationItemThumbnail_conversationThumbnail_minWidth, 0),
|
||||
typedArray.getDimensionPixelSize(R.styleable.ConversationItemThumbnail_conversationThumbnail_maxWidth, 0),
|
||||
typedArray.getDimensionPixelSize(R.styleable.ConversationItemThumbnail_conversationThumbnail_minHeight, 0),
|
||||
typedArray.getDimensionPixelSize(R.styleable.ConversationItemThumbnail_conversationThumbnail_maxHeight, 0)
|
||||
};
|
||||
|
||||
gifWidth = typedArray.getDimensionPixelSize(R.styleable.ConversationItemThumbnail_conversationThumbnail_gifWidth, gifWidth);
|
||||
thumbnail.setBounds(typedArray.getDimensionPixelSize(R.styleable.ConversationItemThumbnail_conversationThumbnail_minWidth, 0),
|
||||
typedArray.getDimensionPixelSize(R.styleable.ConversationItemThumbnail_conversationThumbnail_maxWidth, 0),
|
||||
typedArray.getDimensionPixelSize(R.styleable.ConversationItemThumbnail_conversationThumbnail_minHeight, 0),
|
||||
typedArray.getDimensionPixelSize(R.styleable.ConversationItemThumbnail_conversationThumbnail_maxHeight, 0));
|
||||
typedArray.recycle();
|
||||
} else {
|
||||
normalBounds = new int[]{0, 0, 0, 0};
|
||||
}
|
||||
|
||||
gifBounds = new int[]{
|
||||
gifWidth,
|
||||
gifWidth,
|
||||
1,
|
||||
Integer.MAX_VALUE
|
||||
};
|
||||
|
||||
minimumThumbnailWidth = -1;
|
||||
}
|
||||
|
||||
@SuppressWarnings("SuspiciousNameCombination")
|
||||
@@ -108,18 +88,6 @@ public class ConversationItemThumbnail extends FrameLayout {
|
||||
}
|
||||
}
|
||||
|
||||
public void hideThumbnailView() {
|
||||
thumbnail.setAlpha(0f);
|
||||
}
|
||||
|
||||
public void showThumbnailView() {
|
||||
thumbnail.setAlpha(1f);
|
||||
}
|
||||
|
||||
public @Nullable CornerMask getCornerMask() {
|
||||
return cornerMask;
|
||||
}
|
||||
|
||||
public void setPulseOutliner(@NonNull Outliner outliner) {
|
||||
this.pulseOutliner = outliner;
|
||||
}
|
||||
@@ -153,7 +121,6 @@ public class ConversationItemThumbnail extends FrameLayout {
|
||||
}
|
||||
|
||||
public void setMinimumThumbnailWidth(int width) {
|
||||
minimumThumbnailWidth = width;
|
||||
thumbnail.setMinimumThumbnailWidth(width);
|
||||
}
|
||||
|
||||
@@ -170,17 +137,6 @@ public class ConversationItemThumbnail extends FrameLayout {
|
||||
boolean showControls, boolean isPreview)
|
||||
{
|
||||
if (slides.size() == 1) {
|
||||
Slide slide = slides.get(0);
|
||||
if (slide.isVideoGif()) {
|
||||
setThumbnailBounds(gifBounds);
|
||||
} else {
|
||||
setThumbnailBounds(normalBounds);
|
||||
|
||||
if (minimumThumbnailWidth != -1) {
|
||||
thumbnail.setMinimumThumbnailWidth(minimumThumbnailWidth);
|
||||
}
|
||||
}
|
||||
|
||||
thumbnail.setVisibility(VISIBLE);
|
||||
album.setVisibility(GONE);
|
||||
|
||||
@@ -211,8 +167,4 @@ public class ConversationItemThumbnail extends FrameLayout {
|
||||
thumbnail.setDownloadClickListener(listener);
|
||||
album.setDownloadClickListener(listener);
|
||||
}
|
||||
|
||||
private void setThumbnailBounds(@NonNull int[] bounds) {
|
||||
thumbnail.setBounds(bounds[0], bounds[1], bounds[2], bounds[3]);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,11 +7,9 @@ import android.graphics.Path;
|
||||
import android.graphics.PorterDuff;
|
||||
import android.graphics.PorterDuffXfermode;
|
||||
import android.graphics.RectF;
|
||||
import android.graphics.drawable.shapes.RoundRectShape;
|
||||
import android.view.View;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
|
||||
public class CornerMask {
|
||||
|
||||
@@ -22,24 +20,19 @@ public class CornerMask {
|
||||
private final RectF bounds = new RectF();
|
||||
|
||||
public CornerMask(@NonNull View view) {
|
||||
this(view, null);
|
||||
}
|
||||
|
||||
public CornerMask(@NonNull View view, @Nullable CornerMask toClone) {
|
||||
view.setLayerType(View.LAYER_TYPE_HARDWARE, null);
|
||||
|
||||
clearPaint.setColor(Color.BLACK);
|
||||
clearPaint.setStyle(Paint.Style.FILL);
|
||||
clearPaint.setAntiAlias(true);
|
||||
clearPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.CLEAR));
|
||||
|
||||
if (toClone != null) {
|
||||
System.arraycopy(toClone.radii, 0, radii, 0, radii.length);
|
||||
}
|
||||
}
|
||||
|
||||
public void mask(Canvas canvas) {
|
||||
bounds.set(canvas.getClipBounds());
|
||||
bounds.left = 0;
|
||||
bounds.top = 0;
|
||||
bounds.right = canvas.getWidth();
|
||||
bounds.bottom = canvas.getHeight();
|
||||
|
||||
corners.reset();
|
||||
corners.addRoundRect(bounds, radii, Path.Direction.CW);
|
||||
@@ -79,8 +72,4 @@ public class CornerMask {
|
||||
public void setBottomLeftRadius(int radius) {
|
||||
radii[6] = radii[7] = radius;
|
||||
}
|
||||
|
||||
public float[] getRadii() {
|
||||
return radii;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -31,7 +31,7 @@ import java.net.URISyntaxException;
|
||||
|
||||
public class CustomDefaultPreference extends DialogPreference {
|
||||
|
||||
private static final String TAG = Log.tag(CustomDefaultPreference.class);
|
||||
private static final String TAG = CustomDefaultPreference.class.getSimpleName();
|
||||
|
||||
private final int inputType;
|
||||
private final String customPreference;
|
||||
|
||||
@@ -10,12 +10,11 @@ import android.view.animation.RotateAnimation;
|
||||
import android.widget.FrameLayout;
|
||||
import android.widget.ImageView;
|
||||
|
||||
import org.signal.core.util.logging.Log;
|
||||
import org.thoughtcrime.securesms.R;
|
||||
|
||||
public class DeliveryStatusView extends FrameLayout {
|
||||
|
||||
private static final String TAG = Log.tag(DeliveryStatusView.class);
|
||||
private static final String TAG = DeliveryStatusView.class.getSimpleName();
|
||||
|
||||
private static final RotateAnimation ROTATION_ANIMATION = new RotateAnimation(0, 360f,
|
||||
Animation.RELATIVE_TO_SELF, 0.5f,
|
||||
|
||||
@@ -20,7 +20,6 @@ import com.pnikosis.materialishprogress.ProgressWheel;
|
||||
|
||||
import org.greenrobot.eventbus.Subscribe;
|
||||
import org.greenrobot.eventbus.ThreadMode;
|
||||
import org.signal.core.util.logging.Log;
|
||||
import org.thoughtcrime.securesms.R;
|
||||
import org.thoughtcrime.securesms.database.AttachmentDatabase;
|
||||
import org.thoughtcrime.securesms.events.PartProgressEvent;
|
||||
@@ -30,7 +29,7 @@ import org.thoughtcrime.securesms.util.Util;
|
||||
|
||||
public class DocumentView extends FrameLayout {
|
||||
|
||||
private static final String TAG = Log.tag(DocumentView.class);
|
||||
private static final String TAG = DocumentView.class.getSimpleName();
|
||||
|
||||
private final @NonNull AnimatingToggle controlToggle;
|
||||
private final @NonNull ImageView downloadButton;
|
||||
|
||||
@@ -6,8 +6,8 @@ import android.util.AttributeSet;
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
|
||||
import org.signal.core.util.ThreadUtil;
|
||||
import org.thoughtcrime.securesms.R;
|
||||
import org.thoughtcrime.securesms.util.Util;
|
||||
|
||||
import java.lang.ref.WeakReference;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
@@ -67,7 +67,7 @@ public class ExpirationTimerView extends androidx.appcompat.widget.AppCompatImag
|
||||
else stopped = false;
|
||||
}
|
||||
|
||||
ThreadUtil.runOnMainDelayed(new AnimationUpdateRunnable(this), calculateAnimationDelay(this.startedAt, this.expiresIn));
|
||||
Util.runOnMainDelayed(new AnimationUpdateRunnable(this), calculateAnimationDelay(this.startedAt, this.expiresIn));
|
||||
}
|
||||
|
||||
public void stopAnimation() {
|
||||
@@ -116,7 +116,7 @@ public class ExpirationTimerView extends androidx.appcompat.widget.AppCompatImag
|
||||
}
|
||||
}
|
||||
|
||||
ThreadUtil.runOnMainDelayed(this, timerView.calculateAnimationDelay(timerView.startedAt, timerView.expiresIn));
|
||||
Util.runOnMainDelayed(this, timerView.calculateAnimationDelay(timerView.startedAt, timerView.expiresIn));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -10,14 +10,13 @@ import android.util.AttributeSet;
|
||||
|
||||
import androidx.annotation.Nullable;
|
||||
|
||||
import org.signal.core.util.logging.Log;
|
||||
import org.thoughtcrime.securesms.R;
|
||||
import org.thoughtcrime.securesms.components.emoji.EmojiTextView;
|
||||
import org.thoughtcrime.securesms.recipients.Recipient;
|
||||
|
||||
public class FromTextView extends EmojiTextView {
|
||||
|
||||
private static final String TAG = Log.tag(FromTextView.class);
|
||||
private static final String TAG = FromTextView.class.getSimpleName();
|
||||
|
||||
public FromTextView(Context context) {
|
||||
super(context);
|
||||
|
||||
@@ -22,10 +22,10 @@ import androidx.annotation.DimenRes;
|
||||
import androidx.annotation.MainThread;
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.core.view.ViewCompat;
|
||||
import androidx.recyclerview.widget.LinearLayoutManager;
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
|
||||
import org.signal.core.util.ThreadUtil;
|
||||
import org.signal.core.util.logging.Log;
|
||||
import org.thoughtcrime.securesms.R;
|
||||
import org.thoughtcrime.securesms.animation.AnimationCompleteListener;
|
||||
@@ -42,6 +42,7 @@ import org.thoughtcrime.securesms.mms.QuoteModel;
|
||||
import org.thoughtcrime.securesms.mms.SlideDeck;
|
||||
import org.thoughtcrime.securesms.recipients.Recipient;
|
||||
import org.thoughtcrime.securesms.util.TextSecurePreferences;
|
||||
import org.thoughtcrime.securesms.util.Util;
|
||||
import org.thoughtcrime.securesms.util.ViewUtil;
|
||||
import org.thoughtcrime.securesms.util.concurrent.AssertedSuccessListener;
|
||||
import org.thoughtcrime.securesms.util.concurrent.ListenableFuture;
|
||||
@@ -58,7 +59,7 @@ public class InputPanel extends LinearLayout
|
||||
ConversationStickerSuggestionAdapter.EventListener
|
||||
{
|
||||
|
||||
private static final String TAG = Log.tag(InputPanel.class);
|
||||
private static final String TAG = InputPanel.class.getSimpleName();
|
||||
|
||||
private static final long QUOTE_REVEAL_DURATION_MILLIS = 150;
|
||||
private static final int FADE_TIME = 150;
|
||||
@@ -73,7 +74,6 @@ public class InputPanel extends LinearLayout
|
||||
private View buttonToggle;
|
||||
private View recordingContainer;
|
||||
private View recordLockCancel;
|
||||
private View composeContainer;
|
||||
|
||||
private MicrophoneRecorderView microphoneRecorderView;
|
||||
private SlideToCancel slideToCancel;
|
||||
@@ -103,7 +103,6 @@ public class InputPanel extends LinearLayout
|
||||
|
||||
View quoteDismiss = findViewById(R.id.quote_dismiss);
|
||||
|
||||
this.composeContainer = findViewById(R.id.compose_bubble);
|
||||
this.stickerSuggestion = findViewById(R.id.input_panel_sticker_suggestion);
|
||||
this.quoteView = findViewById(R.id.quote_view);
|
||||
this.linkPreview = findViewById(R.id.link_preview);
|
||||
@@ -287,16 +286,6 @@ public class InputPanel extends LinearLayout
|
||||
return mediaKeyboard;
|
||||
}
|
||||
|
||||
public void setWallpaperEnabled(boolean enabled) {
|
||||
if (enabled) {
|
||||
setBackgroundColor(getContext().getResources().getColor(R.color.wallpaper_compose_background));
|
||||
composeContainer.setBackgroundResource(R.drawable.compose_background_wallpaper);
|
||||
} else {
|
||||
setBackgroundColor(getResources().getColor(R.color.signal_background_primary));
|
||||
composeContainer.setBackgroundResource(R.drawable.compose_background);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onRecordPermissionRequired() {
|
||||
if (listener != null) listener.onRecorderPermissionRequired();
|
||||
@@ -334,10 +323,11 @@ public class InputPanel extends LinearLayout
|
||||
public void onRecordMoved(float offsetX, float absoluteX) {
|
||||
slideToCancel.moveTo(offsetX);
|
||||
|
||||
int direction = ViewCompat.getLayoutDirection(this);
|
||||
float position = absoluteX / recordingContainer.getWidth();
|
||||
|
||||
if (ViewUtil.isLtr(this) && position <= 0.5 ||
|
||||
ViewUtil.isRtl(this) && position >= 0.6)
|
||||
if (direction == ViewCompat.LAYOUT_DIRECTION_LTR && position <= 0.5 ||
|
||||
direction == ViewCompat.LAYOUT_DIRECTION_RTL && position >= 0.6)
|
||||
{
|
||||
this.microphoneRecorderView.cancelAction();
|
||||
}
|
||||
@@ -500,7 +490,7 @@ public class InputPanel extends LinearLayout
|
||||
this.startTime = System.currentTimeMillis();
|
||||
this.recordTimeView.setText(DateUtils.formatElapsedTime(0));
|
||||
ViewUtil.fadeIn(this.recordTimeView, FADE_TIME);
|
||||
ThreadUtil.runOnMainDelayed(this, TimeUnit.SECONDS.toMillis(1));
|
||||
Util.runOnMainDelayed(this, TimeUnit.SECONDS.toMillis(1));
|
||||
microphone.setVisibility(View.VISIBLE);
|
||||
microphone.startAnimation(pulseAnimation());
|
||||
}
|
||||
@@ -526,7 +516,7 @@ public class InputPanel extends LinearLayout
|
||||
onLimitHit.run();
|
||||
} else {
|
||||
recordTimeView.setText(DateUtils.formatElapsedTime(elapsedSeconds));
|
||||
ThreadUtil.runOnMainDelayed(this, TimeUnit.SECONDS.toMillis(1));
|
||||
Util.runOnMainDelayed(this, TimeUnit.SECONDS.toMillis(1));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10,7 +10,6 @@ import androidx.constraintlayout.widget.ConstraintLayout;
|
||||
import androidx.constraintlayout.widget.Guideline;
|
||||
|
||||
import org.thoughtcrime.securesms.R;
|
||||
import org.thoughtcrime.securesms.util.ViewUtil;
|
||||
|
||||
public class InsetAwareConstraintLayout extends ConstraintLayout {
|
||||
|
||||
@@ -46,19 +45,11 @@ public class InsetAwareConstraintLayout extends ConstraintLayout {
|
||||
}
|
||||
|
||||
if (parentStartGuideline != null) {
|
||||
if (ViewUtil.isLtr(this)) {
|
||||
parentStartGuideline.setGuidelineBegin(insets.left);
|
||||
} else {
|
||||
parentStartGuideline.setGuidelineBegin(insets.right);
|
||||
}
|
||||
parentStartGuideline.setGuidelineBegin(insets.left);
|
||||
}
|
||||
|
||||
if (parentEndGuideline != null) {
|
||||
if (ViewUtil.isLtr(this)) {
|
||||
parentEndGuideline.setGuidelineEnd(insets.right);
|
||||
} else {
|
||||
parentEndGuideline.setGuidelineEnd(insets.left);
|
||||
}
|
||||
parentEndGuideline.setGuidelineEnd(insets.right);
|
||||
}
|
||||
|
||||
return true;
|
||||
|
||||
@@ -43,7 +43,7 @@ import java.util.Set;
|
||||
* has been opened and what its height would be.
|
||||
*/
|
||||
public class KeyboardAwareLinearLayout extends LinearLayoutCompat {
|
||||
private static final String TAG = Log.tag(KeyboardAwareLinearLayout.class);
|
||||
private static final String TAG = KeyboardAwareLinearLayout.class.getSimpleName();
|
||||
|
||||
private final Rect rect = new Rect();
|
||||
private final Set<OnKeyboardHiddenListener> hiddenListeners = new HashSet<>();
|
||||
|
||||
@@ -28,7 +28,6 @@ import java.text.SimpleDateFormat;
|
||||
import java.util.Locale;
|
||||
|
||||
import okhttp3.HttpUrl;
|
||||
import org.thoughtcrime.securesms.util.ViewUtil;
|
||||
|
||||
/**
|
||||
* The view shown in the compose box or conversation that represents the state of the link preview.
|
||||
@@ -182,16 +181,10 @@ public class LinkPreviewView extends FrameLayout {
|
||||
}
|
||||
}
|
||||
|
||||
public void setCorners(int topStart, int topEnd) {
|
||||
if (ViewUtil.isRtl(this)) {
|
||||
cornerMask.setRadii(topEnd, topStart, 0, 0);
|
||||
outliner.setRadii(topEnd, topStart, 0, 0);
|
||||
thumbnail.setCorners(defaultRadius, topEnd, defaultRadius, defaultRadius);
|
||||
} else {
|
||||
cornerMask.setRadii(topStart, topEnd, 0, 0);
|
||||
outliner.setRadii(topStart, topEnd, 0, 0);
|
||||
thumbnail.setCorners(topStart, defaultRadius, defaultRadius, defaultRadius);
|
||||
}
|
||||
public void setCorners(int topLeft, int topRight) {
|
||||
cornerMask.setRadii(topLeft, topRight, 0, 0);
|
||||
outliner.setRadii(topLeft, topRight, 0, 0);
|
||||
thumbnail.setCorners(topLeft, defaultRadius, defaultRadius, defaultRadius);
|
||||
postInvalidate();
|
||||
}
|
||||
|
||||
|
||||
@@ -15,17 +15,13 @@ import android.view.ViewTreeObserver;
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
public class MaskView extends View {
|
||||
|
||||
private MaskTarget maskTarget;
|
||||
private ViewGroup activityContentView;
|
||||
private Paint maskPaint;
|
||||
private Rect drawingRect = new Rect();
|
||||
private float targetParentTranslationY;
|
||||
private View target;
|
||||
private ViewGroup activityContentView;
|
||||
private Paint maskPaint;
|
||||
private Rect drawingRect = new Rect();
|
||||
private float targetParentTranslationY;
|
||||
|
||||
private final ViewTreeObserver.OnDrawListener onDrawListener = this::invalidate;
|
||||
|
||||
@@ -54,15 +50,15 @@ public class MaskView extends View {
|
||||
activityContentView = getRootView().findViewById(android.R.id.content);
|
||||
}
|
||||
|
||||
public void setTarget(@Nullable MaskTarget maskTarget) {
|
||||
if (this.maskTarget != null) {
|
||||
removeOnDrawListener(this.maskTarget, onDrawListener);
|
||||
public void setTarget(@Nullable View target) {
|
||||
if (this.target != null) {
|
||||
this.target.getViewTreeObserver().removeOnDrawListener(onDrawListener);
|
||||
}
|
||||
|
||||
this.maskTarget = maskTarget;
|
||||
this.target = target;
|
||||
|
||||
if (this.maskTarget != null) {
|
||||
addOnDrawListener(maskTarget, onDrawListener);
|
||||
if (this.target != null) {
|
||||
this.target.getViewTreeObserver().addOnDrawListener(onDrawListener);
|
||||
}
|
||||
|
||||
invalidate();
|
||||
@@ -76,77 +72,26 @@ public class MaskView extends View {
|
||||
protected void onDraw(@NonNull Canvas canvas) {
|
||||
super.onDraw(canvas);
|
||||
|
||||
if (nothingToMask(maskTarget)) {
|
||||
if (target == null || !target.isAttachedToWindow()) {
|
||||
return;
|
||||
}
|
||||
|
||||
maskTarget.getPrimaryTarget().getDrawingRect(drawingRect);
|
||||
activityContentView.offsetDescendantRectToMyCoords(maskTarget.getPrimaryTarget(), drawingRect);
|
||||
target.getDrawingRect(drawingRect);
|
||||
activityContentView.offsetDescendantRectToMyCoords(target, drawingRect);
|
||||
|
||||
drawingRect.top += targetParentTranslationY;
|
||||
drawingRect.bottom += targetParentTranslationY;
|
||||
|
||||
Bitmap mask = Bitmap.createBitmap(maskTarget.getPrimaryTarget().getWidth(), drawingRect.height(), Bitmap.Config.ARGB_8888);
|
||||
Bitmap mask = Bitmap.createBitmap(target.getWidth(), drawingRect.height(), Bitmap.Config.ARGB_8888);
|
||||
Canvas maskCanvas = new Canvas(mask);
|
||||
|
||||
maskTarget.draw(maskCanvas);
|
||||
target.draw(maskCanvas);
|
||||
|
||||
canvas.clipRect(drawingRect.left, Math.max(drawingRect.top, getTop() + getPaddingTop()), drawingRect.right, Math.min(drawingRect.bottom, getBottom() - getPaddingBottom()));
|
||||
|
||||
ViewGroup.MarginLayoutParams params = (ViewGroup.MarginLayoutParams) maskTarget.getPrimaryTarget().getLayoutParams();
|
||||
ViewGroup.MarginLayoutParams params = (ViewGroup.MarginLayoutParams) target.getLayoutParams();
|
||||
canvas.drawBitmap(mask, params.leftMargin, drawingRect.top, maskPaint);
|
||||
|
||||
mask.recycle();
|
||||
}
|
||||
|
||||
private static void removeOnDrawListener(@NonNull MaskTarget maskTarget, @NonNull ViewTreeObserver.OnDrawListener onDrawListener) {
|
||||
for (View view : maskTarget.getAllTargets()) {
|
||||
if (view != null) {
|
||||
view.getViewTreeObserver().removeOnDrawListener(onDrawListener);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static void addOnDrawListener(@NonNull MaskTarget maskTarget, @NonNull ViewTreeObserver.OnDrawListener onDrawListener) {
|
||||
for (View view : maskTarget.getAllTargets()) {
|
||||
if (view != null) {
|
||||
view.getViewTreeObserver().addOnDrawListener(onDrawListener);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static boolean nothingToMask(@Nullable MaskTarget maskTarget) {
|
||||
if (maskTarget == null) {
|
||||
return true;
|
||||
}
|
||||
|
||||
for (View view : maskTarget.getAllTargets()) {
|
||||
if (view == null || !view.isAttachedToWindow()) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public static class MaskTarget {
|
||||
|
||||
private final View primaryTarget;
|
||||
|
||||
public MaskTarget(@NonNull View primaryTarget) {
|
||||
this.primaryTarget = primaryTarget;
|
||||
}
|
||||
|
||||
final @NonNull View getPrimaryTarget() {
|
||||
return primaryTarget;
|
||||
}
|
||||
|
||||
protected @NonNull List<View> getAllTargets() {
|
||||
return Collections.singletonList(primaryTarget);
|
||||
}
|
||||
|
||||
protected void draw(@NonNull Canvas canvas) {
|
||||
primaryTarget.draw(canvas);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -23,7 +23,6 @@ import androidx.core.view.ViewCompat;
|
||||
|
||||
import org.thoughtcrime.securesms.R;
|
||||
import org.thoughtcrime.securesms.permissions.Permissions;
|
||||
import org.thoughtcrime.securesms.util.ViewUtil;
|
||||
|
||||
public final class MicrophoneRecorderView extends FrameLayout implements View.OnTouchListener {
|
||||
|
||||
@@ -225,8 +224,8 @@ public final class MicrophoneRecorderView extends FrameLayout implements View.On
|
||||
}
|
||||
|
||||
private float getXOffset(float x) {
|
||||
return ViewUtil.isLtr(recordButtonFab) ? -Math.max(0, this.startPositionX - x)
|
||||
: Math.max(0, x - this.startPositionX);
|
||||
return ViewCompat.getLayoutDirection(recordButtonFab) == ViewCompat.LAYOUT_DIRECTION_LTR ?
|
||||
-Math.max(0, this.startPositionX - x) : Math.max(0, x - this.startPositionX);
|
||||
}
|
||||
|
||||
private float getYOffset(float y) {
|
||||
|
||||
@@ -1,64 +0,0 @@
|
||||
package org.thoughtcrime.securesms.components;
|
||||
|
||||
import android.content.Context;
|
||||
import android.util.AttributeSet;
|
||||
import android.widget.FrameLayout;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.constraintlayout.widget.ConstraintLayout;
|
||||
|
||||
import org.thoughtcrime.securesms.R;
|
||||
|
||||
public class PaymentPillStrip extends ConstraintLayout {
|
||||
|
||||
private FrameLayout buttonStart;
|
||||
private FrameLayout buttonEnd;
|
||||
|
||||
public PaymentPillStrip(@NonNull Context context) {
|
||||
super(context);
|
||||
}
|
||||
|
||||
public PaymentPillStrip(@NonNull Context context, @Nullable AttributeSet attrs) {
|
||||
super(context, attrs);
|
||||
}
|
||||
|
||||
public PaymentPillStrip(@NonNull Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
|
||||
super(context, attrs, defStyleAttr);
|
||||
}
|
||||
|
||||
public PaymentPillStrip(@NonNull Context context, @Nullable AttributeSet attrs, int defStyleAttr, int defStyleRes) {
|
||||
super(context, attrs, defStyleAttr, defStyleRes);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onFinishInflate() {
|
||||
super.onFinishInflate();
|
||||
|
||||
buttonStart = findViewById(R.id.button_start_frame);
|
||||
buttonEnd = findViewById(R.id.button_end_frame);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
|
||||
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
|
||||
|
||||
if (buttonStart.getMeasuredWidth() > buttonEnd.getMinimumWidth()) {
|
||||
buttonEnd.setMinimumWidth(buttonStart.getMeasuredWidth());
|
||||
}
|
||||
|
||||
if (buttonEnd.getMeasuredWidth() > buttonStart.getMinimumWidth()) {
|
||||
buttonStart.setMinimumWidth(buttonEnd.getMeasuredWidth());
|
||||
}
|
||||
|
||||
if (buttonStart.getMeasuredHeight() > buttonEnd.getMinimumHeight()) {
|
||||
buttonEnd.setMinimumHeight(buttonStart.getMeasuredHeight());
|
||||
}
|
||||
|
||||
if (buttonEnd.getMeasuredHeight() > buttonStart.getMinimumHeight()) {
|
||||
buttonStart.setMinimumHeight(buttonEnd.getMeasuredHeight());
|
||||
}
|
||||
|
||||
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
|
||||
}
|
||||
}
|
||||
@@ -28,7 +28,6 @@ import androidx.annotation.NonNull;
|
||||
|
||||
import com.annimon.stream.Stream;
|
||||
|
||||
import org.signal.core.util.logging.Log;
|
||||
import org.thoughtcrime.securesms.R;
|
||||
import org.thoughtcrime.securesms.contacts.RecipientsAdapter;
|
||||
import org.thoughtcrime.securesms.contacts.RecipientsEditor;
|
||||
@@ -46,7 +45,7 @@ import java.util.StringTokenizer;
|
||||
* @author Moxie Marlinspike
|
||||
*/
|
||||
public class PushRecipientsPanel extends RelativeLayout implements RecipientForeverObserver {
|
||||
private final String TAG = Log.tag(PushRecipientsPanel.class);
|
||||
private final String TAG = PushRecipientsPanel.class.getSimpleName();
|
||||
private RecipientsPanelChangedListener panelChangeListener;
|
||||
|
||||
private RecipientsEditor recipientsText;
|
||||
|
||||
@@ -21,7 +21,6 @@ import androidx.annotation.RequiresApi;
|
||||
import com.annimon.stream.Stream;
|
||||
import com.bumptech.glide.load.engine.DiskCacheStrategy;
|
||||
|
||||
import org.signal.core.util.logging.Log;
|
||||
import org.thoughtcrime.securesms.R;
|
||||
import org.thoughtcrime.securesms.attachments.Attachment;
|
||||
import org.thoughtcrime.securesms.components.mention.MentionAnnotation;
|
||||
@@ -39,7 +38,7 @@ import java.util.List;
|
||||
|
||||
public class QuoteView extends FrameLayout implements RecipientForeverObserver {
|
||||
|
||||
private static final String TAG = Log.tag(QuoteView.class);
|
||||
private static final String TAG = QuoteView.class.getSimpleName();
|
||||
|
||||
private static final int MESSAGE_TYPE_PREVIEW = 0;
|
||||
private static final int MESSAGE_TYPE_OUTGOING = 1;
|
||||
|
||||
@@ -10,9 +10,7 @@ import android.widget.Toast;
|
||||
import androidx.appcompat.app.AlertDialog;
|
||||
|
||||
import org.signal.core.util.logging.Log;
|
||||
import org.thoughtcrime.securesms.BuildConfig;
|
||||
import org.thoughtcrime.securesms.R;
|
||||
import org.thoughtcrime.securesms.util.PlayStoreUtil;
|
||||
import org.thoughtcrime.securesms.util.TextSecurePreferences;
|
||||
import org.thoughtcrime.securesms.util.VersionTracker;
|
||||
|
||||
@@ -23,10 +21,10 @@ public class RatingManager {
|
||||
private static final int DAYS_SINCE_INSTALL_THRESHOLD = 7;
|
||||
private static final int DAYS_UNTIL_REPROMPT_THRESHOLD = 4;
|
||||
|
||||
private static final String TAG = Log.tag(RatingManager.class);
|
||||
private static final String TAG = RatingManager.class.getSimpleName();
|
||||
|
||||
public static void showRatingDialogIfNecessary(Context context) {
|
||||
if (!TextSecurePreferences.isRatingEnabled(context) || BuildConfig.PLAY_STORE_DISABLED) return;
|
||||
if (!TextSecurePreferences.isRatingEnabled(context)) return;
|
||||
|
||||
long daysSinceInstall = VersionTracker.getDaysSinceFirstInstalled(context);
|
||||
long laterTimestamp = TextSecurePreferences.getRatingLaterTimestamp(context);
|
||||
@@ -46,7 +44,7 @@ public class RatingManager {
|
||||
@Override
|
||||
public void onClick(DialogInterface dialog, int which) {
|
||||
TextSecurePreferences.setRatingEnabled(context, false);
|
||||
PlayStoreUtil.openPlayStoreOrOurApkDownloadPage(context);
|
||||
startPlayStore(context);
|
||||
}
|
||||
})
|
||||
.setNegativeButton(R.string.RatingManager_no_thanks, new DialogInterface.OnClickListener() {
|
||||
@@ -64,4 +62,15 @@ public class RatingManager {
|
||||
})
|
||||
.show();
|
||||
}
|
||||
|
||||
private static void startPlayStore(Context context) {
|
||||
Uri uri = Uri.parse("market://details?id=" + context.getPackageName());
|
||||
try {
|
||||
context.startActivity(new Intent(Intent.ACTION_VIEW, uri));
|
||||
} catch (ActivityNotFoundException e) {
|
||||
Log.w(TAG, e);
|
||||
Toast.makeText(context, R.string.RatingManager_whoops_the_play_store_app_does_not_appear_to_be_installed, Toast.LENGTH_LONG).show();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -28,7 +28,6 @@ import com.bumptech.glide.load.engine.DiskCacheStrategy;
|
||||
import com.bumptech.glide.load.resource.drawable.DrawableTransitionOptions;
|
||||
import com.bumptech.glide.signature.MediaStoreSignature;
|
||||
|
||||
import org.signal.core.util.logging.Log;
|
||||
import org.thoughtcrime.securesms.R;
|
||||
import org.thoughtcrime.securesms.database.CursorRecyclerViewAdapter;
|
||||
import org.thoughtcrime.securesms.database.loaders.RecentPhotosLoader;
|
||||
@@ -83,7 +82,7 @@ public class RecentPhotoViewRail extends FrameLayout implements LoaderManager.Lo
|
||||
private static class RecentPhotoAdapter extends CursorRecyclerViewAdapter<RecentPhotoAdapter.RecentPhotoViewHolder> {
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
private static final String TAG = Log.tag(RecentPhotoAdapter.class);
|
||||
private static final String TAG = RecentPhotoAdapter.class.getSimpleName();
|
||||
|
||||
@NonNull private final Uri baseUri;
|
||||
@Nullable private OnItemClickedListener clickedListener;
|
||||
|
||||
@@ -15,7 +15,6 @@ import androidx.recyclerview.widget.DefaultItemAnimator;
|
||||
import androidx.recyclerview.widget.LinearLayoutManager;
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
|
||||
import org.signal.core.util.logging.Log;
|
||||
import org.thoughtcrime.securesms.R;
|
||||
import org.thoughtcrime.securesms.database.CursorRecyclerViewAdapter;
|
||||
import org.thoughtcrime.securesms.database.MediaDatabase;
|
||||
@@ -62,7 +61,7 @@ public class ThreadPhotoRailView extends FrameLayout {
|
||||
private static class ThreadPhotoRailAdapter extends CursorRecyclerViewAdapter<ThreadPhotoRailAdapter.ThreadPhotoViewHolder> {
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
private static final String TAG = Log.tag(ThreadPhotoRailAdapter.class);
|
||||
private static final String TAG = ThreadPhotoRailAdapter.class.getSimpleName();
|
||||
|
||||
@NonNull private final GlideRequests glideRequests;
|
||||
|
||||
|
||||
@@ -36,8 +36,6 @@ import org.thoughtcrime.securesms.util.Util;
|
||||
import org.thoughtcrime.securesms.util.ViewUtil;
|
||||
import org.thoughtcrime.securesms.util.concurrent.ListenableFuture;
|
||||
import org.thoughtcrime.securesms.util.concurrent.SettableFuture;
|
||||
import org.thoughtcrime.securesms.util.views.Stub;
|
||||
import org.thoughtcrime.securesms.video.VideoPlayer;
|
||||
import org.whispersystems.libsignal.util.guava.Optional;
|
||||
|
||||
import java.util.Collections;
|
||||
@@ -49,7 +47,7 @@ import static com.bumptech.glide.load.resource.drawable.DrawableTransitionOption
|
||||
|
||||
public class ThumbnailView extends FrameLayout {
|
||||
|
||||
private static final String TAG = Log.tag(ThumbnailView.class);
|
||||
private static final String TAG = ThumbnailView.class.getSimpleName();
|
||||
private static final int WIDTH = 0;
|
||||
private static final int HEIGHT = 1;
|
||||
private static final int MIN_WIDTH = 0;
|
||||
@@ -57,12 +55,11 @@ public class ThumbnailView extends FrameLayout {
|
||||
private static final int MIN_HEIGHT = 2;
|
||||
private static final int MAX_HEIGHT = 3;
|
||||
|
||||
private ImageView image;
|
||||
private ImageView blurhash;
|
||||
private View playOverlay;
|
||||
private View captionIcon;
|
||||
private Stub<VideoPlayer> videoPlayer;
|
||||
private OnClickListener parentClickListener;
|
||||
private ImageView image;
|
||||
private ImageView blurhash;
|
||||
private View playOverlay;
|
||||
private View captionIcon;
|
||||
private OnClickListener parentClickListener;
|
||||
|
||||
private final int[] dimens = new int[2];
|
||||
private final int[] bounds = new int[4];
|
||||
@@ -93,7 +90,6 @@ public class ThumbnailView extends FrameLayout {
|
||||
this.blurhash = findViewById(R.id.thumbnail_blurhash);
|
||||
this.playOverlay = findViewById(R.id.play_overlay);
|
||||
this.captionIcon = findViewById(R.id.thumbnail_caption_icon);
|
||||
this.videoPlayer = new Stub<>(findViewById(R.id.thumbnail_player_stub));
|
||||
super.setOnClickListener(new ThumbnailClickDispatcher());
|
||||
|
||||
if (attrs != null) {
|
||||
@@ -339,7 +335,6 @@ public class ThumbnailView extends FrameLayout {
|
||||
}
|
||||
|
||||
buildThumbnailGlideRequest(glideRequests, slide).into(new GlideDrawableListeningTarget(image, result));
|
||||
|
||||
resultHandled = true;
|
||||
} else {
|
||||
glideRequests.clear(image);
|
||||
@@ -447,7 +442,7 @@ public class ThumbnailView extends FrameLayout {
|
||||
}
|
||||
|
||||
request = request.override(size[WIDTH], size[HEIGHT]);
|
||||
|
||||
|
||||
if (radius > 0) {
|
||||
return request.transforms(fitting, new RoundedCorners(radius));
|
||||
} else {
|
||||
|
||||
@@ -10,7 +10,6 @@ import androidx.lifecycle.MutableLiveData;
|
||||
import com.annimon.stream.Collectors;
|
||||
import com.annimon.stream.Stream;
|
||||
|
||||
import org.signal.core.util.ThreadUtil;
|
||||
import org.signal.core.util.logging.Log;
|
||||
import org.thoughtcrime.securesms.recipients.Recipient;
|
||||
import org.thoughtcrime.securesms.util.Util;
|
||||
@@ -27,7 +26,7 @@ import java.util.concurrent.TimeUnit;
|
||||
@SuppressLint("UseSparseArrays")
|
||||
public class TypingStatusRepository {
|
||||
|
||||
private static final String TAG = Log.tag(TypingStatusRepository.class);
|
||||
private static final String TAG = TypingStatusRepository.class.getSimpleName();
|
||||
|
||||
private static final long RECIPIENT_TYPING_TIMEOUT = TimeUnit.SECONDS.toMillis(15);
|
||||
|
||||
@@ -59,11 +58,11 @@ public class TypingStatusRepository {
|
||||
|
||||
Runnable timer = timers.get(typist);
|
||||
if (timer != null) {
|
||||
ThreadUtil.cancelRunnableOnMain(timer);
|
||||
Util.cancelRunnableOnMain(timer);
|
||||
}
|
||||
|
||||
timer = () -> onTypingStopped(context, threadId, author, device, false);
|
||||
ThreadUtil.runOnMainDelayed(timer, RECIPIENT_TYPING_TIMEOUT);
|
||||
Util.runOnMainDelayed(timer, RECIPIENT_TYPING_TIMEOUT);
|
||||
timers.put(typist, timer);
|
||||
}
|
||||
|
||||
@@ -86,7 +85,7 @@ public class TypingStatusRepository {
|
||||
|
||||
Runnable timer = timers.get(typist);
|
||||
if (timer != null) {
|
||||
ThreadUtil.cancelRunnableOnMain(timer);
|
||||
Util.cancelRunnableOnMain(timer);
|
||||
timers.remove(typist);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,9 +1,11 @@
|
||||
package org.thoughtcrime.securesms.components;
|
||||
|
||||
import android.annotation.SuppressLint;
|
||||
import android.app.Application;
|
||||
import android.content.Context;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
|
||||
import org.signal.core.util.ThreadUtil;
|
||||
import org.signal.core.util.logging.Log;
|
||||
import org.thoughtcrime.securesms.dependencies.ApplicationDependencies;
|
||||
import org.thoughtcrime.securesms.jobs.TypingSendJob;
|
||||
import org.thoughtcrime.securesms.util.Util;
|
||||
@@ -15,7 +17,7 @@ import java.util.concurrent.TimeUnit;
|
||||
@SuppressLint("UseSparseArrays")
|
||||
public class TypingStatusSender {
|
||||
|
||||
private static final String TAG = Log.tag(TypingStatusSender.class);
|
||||
private static final String TAG = TypingStatusSender.class.getSimpleName();
|
||||
|
||||
private static final long REFRESH_TYPING_TIMEOUT = TimeUnit.SECONDS.toMillis(10);
|
||||
private static final long PAUSE_TYPING_TIMEOUT = TimeUnit.SECONDS.toMillis(3);
|
||||
@@ -34,16 +36,16 @@ public class TypingStatusSender {
|
||||
sendTyping(threadId, true);
|
||||
|
||||
Runnable start = new StartRunnable(threadId);
|
||||
ThreadUtil.runOnMainDelayed(start, REFRESH_TYPING_TIMEOUT);
|
||||
Util.runOnMainDelayed(start, REFRESH_TYPING_TIMEOUT);
|
||||
pair.setStart(start);
|
||||
}
|
||||
|
||||
if (pair.getStop() != null) {
|
||||
ThreadUtil.cancelRunnableOnMain(pair.getStop());
|
||||
Util.cancelRunnableOnMain(pair.getStop());
|
||||
}
|
||||
|
||||
Runnable stop = () -> onTypingStopped(threadId, true);
|
||||
ThreadUtil.runOnMainDelayed(stop, PAUSE_TYPING_TIMEOUT);
|
||||
Util.runOnMainDelayed(stop, PAUSE_TYPING_TIMEOUT);
|
||||
pair.setStop(stop);
|
||||
}
|
||||
|
||||
@@ -60,7 +62,7 @@ public class TypingStatusSender {
|
||||
selfTypingTimers.put(threadId, pair);
|
||||
|
||||
if (pair.getStart() != null) {
|
||||
ThreadUtil.cancelRunnableOnMain(pair.getStart());
|
||||
Util.cancelRunnableOnMain(pair.getStart());
|
||||
|
||||
if (notify) {
|
||||
sendTyping(threadId, false);
|
||||
@@ -68,7 +70,7 @@ public class TypingStatusSender {
|
||||
}
|
||||
|
||||
if (pair.getStop() != null) {
|
||||
ThreadUtil.cancelRunnableOnMain(pair.getStop());
|
||||
Util.cancelRunnableOnMain(pair.getStop());
|
||||
}
|
||||
|
||||
pair.setStart(null);
|
||||
@@ -90,7 +92,7 @@ public class TypingStatusSender {
|
||||
@Override
|
||||
public void run() {
|
||||
sendTyping(threadId, true);
|
||||
ThreadUtil.runOnMainDelayed(this, REFRESH_TYPING_TIMEOUT);
|
||||
Util.runOnMainDelayed(this, REFRESH_TYPING_TIMEOUT);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,74 +0,0 @@
|
||||
package org.thoughtcrime.securesms.components;
|
||||
|
||||
import android.content.Context;
|
||||
import android.util.AttributeSet;
|
||||
import android.view.View;
|
||||
import android.widget.TextView;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.constraintlayout.widget.ConstraintLayout;
|
||||
|
||||
import org.thoughtcrime.securesms.R;
|
||||
import org.thoughtcrime.securesms.conversationlist.model.UnreadPayments;
|
||||
|
||||
/**
|
||||
* Displays the data in a given UnreadPayments object in a banner.
|
||||
*/
|
||||
public class UnreadPaymentsView extends ConstraintLayout {
|
||||
|
||||
private TextView title;
|
||||
private AvatarImageView avatar;
|
||||
private Listener listener;
|
||||
|
||||
public UnreadPaymentsView(@NonNull Context context) {
|
||||
super(context);
|
||||
}
|
||||
|
||||
public UnreadPaymentsView(@NonNull Context context, @Nullable AttributeSet attrs) {
|
||||
super(context, attrs);
|
||||
}
|
||||
|
||||
public UnreadPaymentsView(@NonNull Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
|
||||
super(context, attrs, defStyleAttr);
|
||||
}
|
||||
|
||||
public UnreadPaymentsView(@NonNull Context context, @Nullable AttributeSet attrs, int defStyleAttr, int defStyleRes) {
|
||||
super(context, attrs, defStyleAttr, defStyleRes);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onFinishInflate() {
|
||||
super.onFinishInflate();
|
||||
|
||||
title = findViewById(R.id.payment_notification_title);
|
||||
avatar = findViewById(R.id.payment_notification_avatar);
|
||||
|
||||
View open = findViewById(R.id.payment_notification_touch_target);
|
||||
View close = findViewById(R.id.payment_notification_close_touch_target);
|
||||
|
||||
open.setOnClickListener(v -> {
|
||||
if (listener != null) listener.onOpenPaymentsNotificationClicked();
|
||||
});
|
||||
|
||||
close.setOnClickListener(v -> {
|
||||
if (listener != null) listener.onClosePaymentsNotificationClicked();
|
||||
});
|
||||
}
|
||||
|
||||
public void setListener(@NonNull Listener listener) {
|
||||
this.listener = listener;
|
||||
}
|
||||
|
||||
public void setUnreadPayments(@NonNull UnreadPayments unreadPayments) {
|
||||
title.setText(unreadPayments.getDescription(getContext()));
|
||||
avatar.setAvatar(unreadPayments.getRecipient());
|
||||
avatar.setVisibility(unreadPayments.getRecipient() == null ? GONE : VISIBLE);
|
||||
}
|
||||
|
||||
public interface Listener {
|
||||
void onOpenPaymentsNotificationClicked();
|
||||
|
||||
void onClosePaymentsNotificationClicked();
|
||||
}
|
||||
}
|
||||
@@ -35,17 +35,13 @@ import java.io.InputStream;
|
||||
|
||||
public class ZoomingImageView extends FrameLayout {
|
||||
|
||||
private static final String TAG = Log.tag(ZoomingImageView.class);
|
||||
private static final String TAG = ZoomingImageView.class.getSimpleName();
|
||||
|
||||
private static final int ZOOM_TRANSITION_DURATION = 300;
|
||||
|
||||
private static final float ZOOM_LEVEL_MIN = 1.0f;
|
||||
|
||||
private static final float LARGE_IMAGES_ZOOM_LEVEL_MID = 1.5f;
|
||||
private static final float LARGE_IMAGES_ZOOM_LEVEL_MAX = 2.0f;
|
||||
|
||||
private static final float SMALL_IMAGES_ZOOM_LEVEL_MID = 3.0f;
|
||||
private static final float SMALL_IMAGES_ZOOM_LEVEL_MAX = 8.0f;
|
||||
private static final float ZOOM_LEVEL_MID = 1.5f;
|
||||
private static final float ZOOM_LEVEL_MAX = 2.0f;
|
||||
|
||||
private final PhotoView photoView;
|
||||
private final SubsamplingScaleImageView subsamplingImageView;
|
||||
@@ -69,11 +65,10 @@ public class ZoomingImageView extends FrameLayout {
|
||||
this.subsamplingImageView.setOrientation(SubsamplingScaleImageView.ORIENTATION_USE_EXIF);
|
||||
|
||||
this.photoView.setZoomTransitionDuration(ZOOM_TRANSITION_DURATION);
|
||||
this.photoView.setScaleLevels(ZOOM_LEVEL_MIN, SMALL_IMAGES_ZOOM_LEVEL_MID, SMALL_IMAGES_ZOOM_LEVEL_MAX);
|
||||
this.photoView.setScaleLevels(ZOOM_LEVEL_MIN, ZOOM_LEVEL_MID, ZOOM_LEVEL_MAX);
|
||||
|
||||
this.subsamplingImageView.setDoubleTapZoomDuration(ZOOM_TRANSITION_DURATION);
|
||||
this.subsamplingImageView.setDoubleTapZoomScale(LARGE_IMAGES_ZOOM_LEVEL_MID);
|
||||
this.subsamplingImageView.setMaxScale(LARGE_IMAGES_ZOOM_LEVEL_MAX);
|
||||
this.subsamplingImageView.setDoubleTapZoomScale(ZOOM_LEVEL_MID);
|
||||
|
||||
this.photoView.setOnClickListener(v -> ZoomingImageView.this.callOnClick());
|
||||
this.subsamplingImageView.setOnClickListener(v -> ZoomingImageView.this.callOnClick());
|
||||
|
||||
@@ -21,7 +21,7 @@ import java.util.Locale;
|
||||
|
||||
@SuppressWarnings("deprecation")
|
||||
public class CameraUtils {
|
||||
private static final String TAG = Log.tag(CameraUtils.class);
|
||||
private static final String TAG = CameraUtils.class.getSimpleName();
|
||||
/*
|
||||
* modified from: https://github.com/commonsguy/cwac-camera/blob/master/camera/src/com/commonsware/cwac/camera/CameraUtils.java
|
||||
*/
|
||||
|
||||
@@ -36,7 +36,6 @@ import android.view.ViewGroup;
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
|
||||
import org.signal.core.util.ThreadUtil;
|
||||
import org.signal.core.util.logging.Log;
|
||||
import org.thoughtcrime.securesms.R;
|
||||
import org.thoughtcrime.securesms.util.BitmapUtil;
|
||||
@@ -51,7 +50,7 @@ import java.util.List;
|
||||
|
||||
@SuppressWarnings("deprecation")
|
||||
public class CameraView extends ViewGroup {
|
||||
private static final String TAG = Log.tag(CameraView.class);
|
||||
private static final String TAG = CameraView.class.getSimpleName();
|
||||
|
||||
private final CameraSurfaceView surface;
|
||||
private final OnOrientationChange onOrientationChange;
|
||||
@@ -321,7 +320,7 @@ public class CameraView extends ViewGroup {
|
||||
camera.startPreview();
|
||||
Log.i(TAG, "camera.startPreview() -> " + (System.currentTimeMillis() - previewStartMillis) + "ms");
|
||||
state = State.ACTIVE;
|
||||
ThreadUtil.runOnMain(new Runnable() {
|
||||
Util.runOnMain(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
requestLayout();
|
||||
@@ -496,9 +495,9 @@ public class CameraView extends ViewGroup {
|
||||
return;
|
||||
}
|
||||
|
||||
ThreadUtil.runOnMainSync(this::onPreMain);
|
||||
Util.runOnMainSync(this::onPreMain);
|
||||
final Result result = onRunBackground();
|
||||
ThreadUtil.runOnMainSync(() -> onPostMain(result));
|
||||
Util.runOnMainSync(() -> onPostMain(result));
|
||||
}
|
||||
|
||||
protected boolean onWait() { return true; }
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
package org.thoughtcrime.securesms.components.emoji;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.res.TypedArray;
|
||||
import android.graphics.drawable.Drawable;
|
||||
import android.text.InputFilter;
|
||||
import android.util.AttributeSet;
|
||||
@@ -10,14 +9,13 @@ import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.appcompat.widget.AppCompatEditText;
|
||||
|
||||
import org.signal.core.util.logging.Log;
|
||||
import org.thoughtcrime.securesms.R;
|
||||
import org.thoughtcrime.securesms.components.emoji.EmojiProvider.EmojiDrawable;
|
||||
import org.thoughtcrime.securesms.util.TextSecurePreferences;
|
||||
|
||||
|
||||
public class EmojiEditText extends AppCompatEditText {
|
||||
private static final String TAG = Log.tag(EmojiEditText.class);
|
||||
private static final String TAG = EmojiEditText.class.getSimpleName();
|
||||
|
||||
public EmojiEditText(Context context) {
|
||||
this(context, null);
|
||||
@@ -29,12 +27,7 @@ public class EmojiEditText extends AppCompatEditText {
|
||||
|
||||
public EmojiEditText(Context context, AttributeSet attrs, int defStyleAttr) {
|
||||
super(context, attrs, defStyleAttr);
|
||||
|
||||
TypedArray a = context.getTheme().obtainStyledAttributes(attrs, R.styleable.EmojiTextView, 0, 0);
|
||||
boolean forceCustom = a.getBoolean(R.styleable.EmojiTextView_emoji_forceCustom, false);
|
||||
a.recycle();
|
||||
|
||||
if (forceCustom || !TextSecurePreferences.isSystemEmojiPreferred(getContext())) {
|
||||
if (!TextSecurePreferences.isSystemEmojiPreferred(getContext())) {
|
||||
setFilters(appendEmojiFilter(this.getFilters()));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10,13 +10,12 @@ import androidx.annotation.NonNull;
|
||||
import androidx.recyclerview.widget.GridLayoutManager;
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
|
||||
import org.signal.core.util.logging.Log;
|
||||
import org.thoughtcrime.securesms.R;
|
||||
import org.thoughtcrime.securesms.components.emoji.EmojiKeyboardProvider.EmojiEventListener;
|
||||
import org.thoughtcrime.securesms.components.emoji.EmojiPageViewGridAdapter.VariationSelectorListener;
|
||||
|
||||
public class EmojiPageView extends FrameLayout implements VariationSelectorListener {
|
||||
private static final String TAG = Log.tag(EmojiPageView.class);
|
||||
private static final String TAG = EmojiPageView.class.getSimpleName();
|
||||
|
||||
private EmojiPageModel model;
|
||||
private EmojiPageViewGridAdapter adapter;
|
||||
|
||||
@@ -18,7 +18,6 @@ import android.widget.TextView;
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
|
||||
import org.signal.core.util.ThreadUtil;
|
||||
import org.signal.core.util.logging.Log;
|
||||
import org.thoughtcrime.securesms.R;
|
||||
import org.thoughtcrime.securesms.components.emoji.parsing.EmojiDrawInfo;
|
||||
@@ -26,6 +25,7 @@ import org.thoughtcrime.securesms.components.emoji.parsing.EmojiPageBitmap;
|
||||
import org.thoughtcrime.securesms.components.emoji.parsing.EmojiParser;
|
||||
import org.thoughtcrime.securesms.components.emoji.parsing.EmojiTree;
|
||||
import org.thoughtcrime.securesms.util.FutureTaskListener;
|
||||
import org.thoughtcrime.securesms.util.Util;
|
||||
import org.whispersystems.libsignal.util.Pair;
|
||||
|
||||
import java.util.List;
|
||||
@@ -33,7 +33,7 @@ import java.util.concurrent.ExecutionException;
|
||||
|
||||
class EmojiProvider {
|
||||
|
||||
private static final String TAG = Log.tag(EmojiProvider.class);
|
||||
private static final String TAG = EmojiProvider.class.getSimpleName();
|
||||
private static volatile EmojiProvider instance = null;
|
||||
private static final Paint paint = new Paint(Paint.FILTER_BITMAP_FLAG | Paint.ANTI_ALIAS_FLAG);
|
||||
|
||||
@@ -118,7 +118,7 @@ class EmojiProvider {
|
||||
final EmojiDrawable drawable = new EmojiDrawable(drawInfo, decodeScale);
|
||||
drawInfo.getPage().get().addListener(new FutureTaskListener<Bitmap>() {
|
||||
@Override public void onSuccess(final Bitmap result) {
|
||||
ThreadUtil.runOnMain(() -> drawable.setBitmap(result));
|
||||
Util.runOnMain(() -> drawable.setBitmap(result));
|
||||
}
|
||||
|
||||
@Override public void onFailure(ExecutionException error) {
|
||||
@@ -170,7 +170,7 @@ class EmojiProvider {
|
||||
|
||||
@TargetApi(VERSION_CODES.HONEYCOMB_MR1)
|
||||
public void setBitmap(Bitmap bitmap) {
|
||||
ThreadUtil.assertMainThread();
|
||||
Util.assertMainThread();
|
||||
if (VERSION.SDK_INT < VERSION_CODES.HONEYCOMB_MR1 || bmp == null || !bmp.sameAs(bitmap)) {
|
||||
bmp = bitmap;
|
||||
invalidateSelf();
|
||||
|
||||
@@ -10,7 +10,6 @@ import android.text.Spanned;
|
||||
import android.text.TextUtils;
|
||||
import android.util.AttributeSet;
|
||||
import android.util.TypedValue;
|
||||
import android.view.ViewGroup;
|
||||
|
||||
import androidx.annotation.ColorInt;
|
||||
import androidx.annotation.NonNull;
|
||||
@@ -138,10 +137,6 @@ public class EmojiTextView extends AppCompatTextView {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (getLayoutParams() != null && getLayoutParams().width == ViewGroup.LayoutParams.WRAP_CONTENT) {
|
||||
requestLayout();
|
||||
}
|
||||
}
|
||||
|
||||
public void setOverflowText(@Nullable CharSequence overflowText) {
|
||||
|
||||
@@ -16,7 +16,6 @@ import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
public final class EmojiUtil {
|
||||
|
||||
@@ -43,8 +42,6 @@ public final class EmojiUtil {
|
||||
MAX_EMOJI_LENGTH = max;
|
||||
}
|
||||
|
||||
private static final Pattern EMOJI_PATTERN = Pattern.compile("^(?:(?:[\u00a9\u00ae\u203c\u2049\u2122\u2139\u2194-\u2199\u21a9-\u21aa\u231a-\u231b\u2328\u23cf\u23e9-\u23f3\u23f8-\u23fa\u24c2\u25aa-\u25ab\u25b6\u25c0\u25fb-\u25fe\u2600-\u2604\u260e\u2611\u2614-\u2615\u2618\u261d\u2620\u2622-\u2623\u2626\u262a\u262e-\u262f\u2638-\u263a\u2648-\u2653\u2660\u2663\u2665-\u2666\u2668\u267b\u267f\u2692-\u2694\u2696-\u2697\u2699\u269b-\u269c\u26a0-\u26a1\u26aa-\u26ab\u26b0-\u26b1\u26bd-\u26be\u26c4-\u26c5\u26c8\u26ce-\u26cf\u26d1\u26d3-\u26d4\u26e9-\u26ea\u26f0-\u26f5\u26f7-\u26fa\u26fd\u2702\u2705\u2708-\u270d\u270f\u2712\u2714\u2716\u271d\u2721\u2728\u2733-\u2734\u2744\u2747\u274c\u274e\u2753-\u2755\u2757\u2763-\u2764\u2795-\u2797\u27a1\u27b0\u27bf\u2934-\u2935\u2b05-\u2b07\u2b1b-\u2b1c\u2b50\u2b55\u3030\u303d\u3297\u3299\ud83c\udc04\ud83c\udccf\ud83c\udd70-\ud83c\udd71\ud83c\udd7e-\ud83c\udd7f\ud83c\udd8e\ud83c\udd91-\ud83c\udd9a\ud83c\ude01-\ud83c\ude02\ud83c\ude1a\ud83c\ude2f\ud83c\ude32-\ud83c\ude3a\ud83c\ude50-\ud83c\ude51\u200d\ud83c\udf00-\ud83d\uddff\ud83d\ude00-\ud83d\ude4f\ud83d\ude80-\ud83d\udeff\ud83e\udd00-\ud83e\uddff\udb40\udc20-\udb40\udc7f]|\u200d[\u2640\u2642]|[\ud83c\udde6-\ud83c\uddff]{2}|.[\u20e0\u20e3\ufe0f]+)+)+$");
|
||||
|
||||
private EmojiUtil() {}
|
||||
|
||||
public static List<EmojiPageModel> getDisplayPages() {
|
||||
@@ -93,25 +90,4 @@ public final class EmojiUtil {
|
||||
return EmojiProvider.getInstance(context).getEmojiDrawable(emoji);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* True if the text is likely a single, valid emoji. Otherwise false.
|
||||
*
|
||||
* We do a two-tier check: first using our own knowledge of emojis (which could be incomplete),
|
||||
* followed by a more wide check for all of the valid emoji unicode ranges (which could lead to
|
||||
* some false positives). YMMV.
|
||||
*/
|
||||
public static boolean isEmoji(@NonNull Context context, @Nullable String text) {
|
||||
if (Util.isEmpty(text)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (StringUtil.getGraphemeCount(text) != 1) {
|
||||
return false;
|
||||
}
|
||||
|
||||
EmojiParser.CandidateList candidates = EmojiProvider.getInstance(context).getCandidates(text);
|
||||
|
||||
return (candidates != null && candidates.size() > 0) || EMOJI_PATTERN.matcher(text).matches();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -24,7 +24,7 @@ import java.util.LinkedHashSet;
|
||||
import java.util.List;
|
||||
|
||||
public class RecentEmojiPageModel implements EmojiPageModel {
|
||||
private static final String TAG = Log.tag(RecentEmojiPageModel.class);
|
||||
private static final String TAG = RecentEmojiPageModel.class.getSimpleName();
|
||||
private static final int EMOJI_LRU_SIZE = 50;
|
||||
|
||||
private final SharedPreferences prefs;
|
||||
|
||||
@@ -8,7 +8,6 @@ import android.graphics.BitmapFactory;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
|
||||
import org.signal.core.util.ThreadUtil;
|
||||
import org.signal.core.util.logging.Log;
|
||||
import org.thoughtcrime.securesms.components.emoji.EmojiPageModel;
|
||||
import org.thoughtcrime.securesms.util.ListenableFutureTask;
|
||||
@@ -23,7 +22,7 @@ import java.util.concurrent.Callable;
|
||||
|
||||
public class EmojiPageBitmap {
|
||||
|
||||
private static final String TAG = Log.tag(EmojiPageBitmap.class);
|
||||
private static final String TAG = EmojiPageBitmap.class.getSimpleName();
|
||||
|
||||
private final Context context;
|
||||
private final EmojiPageModel model;
|
||||
@@ -40,7 +39,7 @@ public class EmojiPageBitmap {
|
||||
|
||||
@SuppressLint("StaticFieldLeak")
|
||||
public ListenableFutureTask<Bitmap> get() {
|
||||
ThreadUtil.assertMainThread();
|
||||
Util.assertMainThread();
|
||||
|
||||
if (bitmapReference != null && bitmapReference.get() != null) {
|
||||
return new ListenableFutureTask<>(bitmapReference.get());
|
||||
|
||||
@@ -8,15 +8,15 @@ import androidx.annotation.NonNull;
|
||||
import androidx.appcompat.app.AlertDialog;
|
||||
|
||||
import org.thoughtcrime.securesms.R;
|
||||
import org.thoughtcrime.securesms.crypto.DatabaseSessionLock;
|
||||
import org.thoughtcrime.securesms.database.DatabaseFactory;
|
||||
import org.thoughtcrime.securesms.database.IdentityDatabase;
|
||||
import org.thoughtcrime.securesms.database.IdentityDatabase.IdentityRecord;
|
||||
import org.thoughtcrime.securesms.util.concurrent.SimpleTask;
|
||||
import org.whispersystems.signalservice.api.SignalSessionLock;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import static org.whispersystems.libsignal.SessionCipher.SESSION_LOCK;
|
||||
|
||||
public class UntrustedSendDialog extends AlertDialog.Builder implements DialogInterface.OnClickListener {
|
||||
|
||||
private final List<IdentityRecord> untrustedRecords;
|
||||
@@ -43,7 +43,7 @@ public class UntrustedSendDialog extends AlertDialog.Builder implements DialogIn
|
||||
final IdentityDatabase identityDatabase = DatabaseFactory.getIdentityDatabase(getContext());
|
||||
|
||||
SimpleTask.run(() -> {
|
||||
try(SignalSessionLock.Lock unused = DatabaseSessionLock.INSTANCE.acquire()) {
|
||||
synchronized (SESSION_LOCK) {
|
||||
for (IdentityRecord identityRecord : untrustedRecords) {
|
||||
identityDatabase.setApproval(identityRecord.getRecipientId(), true);
|
||||
}
|
||||
|
||||
@@ -22,7 +22,7 @@ import java.util.List;
|
||||
|
||||
public class UnverifiedBannerView extends LinearLayout {
|
||||
|
||||
private static final String TAG = Log.tag(UnverifiedBannerView.class);
|
||||
private static final String TAG = UnverifiedBannerView.class.getSimpleName();
|
||||
|
||||
private View container;
|
||||
private TextView text;
|
||||
|
||||
@@ -8,14 +8,14 @@ import androidx.annotation.NonNull;
|
||||
import androidx.appcompat.app.AlertDialog;
|
||||
|
||||
import org.thoughtcrime.securesms.R;
|
||||
import org.thoughtcrime.securesms.crypto.DatabaseSessionLock;
|
||||
import org.thoughtcrime.securesms.database.DatabaseFactory;
|
||||
import org.thoughtcrime.securesms.database.IdentityDatabase;
|
||||
import org.thoughtcrime.securesms.database.IdentityDatabase.IdentityRecord;
|
||||
import org.whispersystems.signalservice.api.SignalSessionLock;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import static org.whispersystems.libsignal.SessionCipher.SESSION_LOCK;
|
||||
|
||||
public class UnverifiedSendDialog extends AlertDialog.Builder implements DialogInterface.OnClickListener {
|
||||
|
||||
private final List<IdentityRecord> untrustedRecords;
|
||||
@@ -44,7 +44,7 @@ public class UnverifiedSendDialog extends AlertDialog.Builder implements DialogI
|
||||
new AsyncTask<Void, Void, Void>() {
|
||||
@Override
|
||||
protected Void doInBackground(Void... params) {
|
||||
try(SignalSessionLock.Lock unused = DatabaseSessionLock.INSTANCE.acquire()) {
|
||||
synchronized (SESSION_LOCK) {
|
||||
for (IdentityRecord identityRecord : untrustedRecords) {
|
||||
identityDatabase.setVerified(identityRecord.getRecipientId(),
|
||||
identityRecord.getIdentityKey(),
|
||||
|
||||
@@ -20,7 +20,7 @@ import java.io.IOException;
|
||||
public class SignalPlace {
|
||||
|
||||
private static final String URL = "https://maps.google.com/maps";
|
||||
private static final String TAG = Log.tag(SignalPlace.class);
|
||||
private static final String TAG = SignalPlace.class.getSimpleName();
|
||||
|
||||
@JsonProperty
|
||||
private CharSequence name;
|
||||
|
||||
@@ -13,7 +13,7 @@ public class GroupsV1MigrationInitiationReminder extends Reminder {
|
||||
|
||||
public GroupsV1MigrationInitiationReminder(@NonNull Context context) {
|
||||
super(null, context.getString(R.string.GroupsV1MigrationInitiationReminder_to_access_new_features_like_mentions));
|
||||
addAction(new Action(context.getString(R.string.GroupsV1MigrationInitiationReminder_upgrade_group), R.id.reminder_action_gv1_initiation_update_group));
|
||||
addAction(new Action(context.getString(R.string.GroupsV1MigrationInitiationReminder_update_group), R.id.reminder_action_gv1_initiation_update_group));
|
||||
addAction(new Action(context.getResources().getString(R.string.GroupsV1MigrationInitiationReminder_not_now), R.id.reminder_action_gv1_initiation_not_now));
|
||||
}
|
||||
|
||||
|
||||
@@ -1,107 +0,0 @@
|
||||
package org.thoughtcrime.securesms.components.sensors;
|
||||
|
||||
import android.content.Context;
|
||||
import android.hardware.Sensor;
|
||||
import android.hardware.SensorEvent;
|
||||
import android.hardware.SensorEventListener;
|
||||
import android.hardware.SensorManager;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.lifecycle.DefaultLifecycleObserver;
|
||||
import androidx.lifecycle.LifecycleOwner;
|
||||
import androidx.lifecycle.LiveData;
|
||||
import androidx.lifecycle.MutableLiveData;
|
||||
import androidx.lifecycle.Transformations;
|
||||
|
||||
import org.thoughtcrime.securesms.util.ServiceUtil;
|
||||
|
||||
public final class DeviceOrientationMonitor implements DefaultLifecycleObserver {
|
||||
|
||||
private static final float MAGNITUDE_MAXIMUM = 1.5f;
|
||||
private static final float MAGNITUDE_MINIMUM = 0.75f;
|
||||
private static final float LANDSCAPE_PITCH_MINIMUM = -0.5f;
|
||||
private static final float LANDSCAPE_PITCH_MAXIMUM = 0.5f;
|
||||
|
||||
private final SensorManager sensorManager;
|
||||
private final EventListener eventListener = new EventListener();
|
||||
|
||||
private final float[] accelerometerReading = new float[3];
|
||||
private final float[] magnetometerReading = new float[3];
|
||||
|
||||
private final float[] rotationMatrix = new float[9];
|
||||
private final float[] orientationAngles = new float[3];
|
||||
|
||||
private final MutableLiveData<Orientation> orientation = new MutableLiveData<>();
|
||||
|
||||
public DeviceOrientationMonitor(@NonNull Context context) {
|
||||
this.sensorManager = ServiceUtil.getSensorManager(context);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onStart(@NonNull LifecycleOwner owner) {
|
||||
Sensor accelerometer = sensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER);
|
||||
if (accelerometer != null) {
|
||||
sensorManager.registerListener(eventListener,
|
||||
accelerometer,
|
||||
SensorManager.SENSOR_DELAY_NORMAL,
|
||||
SensorManager.SENSOR_DELAY_UI);
|
||||
}
|
||||
Sensor magneticField = sensorManager.getDefaultSensor(Sensor.TYPE_MAGNETIC_FIELD);
|
||||
if (magneticField != null) {
|
||||
sensorManager.registerListener(eventListener,
|
||||
magneticField,
|
||||
SensorManager.SENSOR_DELAY_NORMAL,
|
||||
SensorManager.SENSOR_DELAY_UI);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onStop(@NonNull LifecycleOwner owner) {
|
||||
sensorManager.unregisterListener(eventListener);
|
||||
}
|
||||
|
||||
public LiveData<Orientation> getOrientation() {
|
||||
return Transformations.distinctUntilChanged(orientation);
|
||||
}
|
||||
|
||||
private void updateOrientationAngles() {
|
||||
boolean success = SensorManager.getRotationMatrix(rotationMatrix, null, accelerometerReading, magnetometerReading);
|
||||
if (!success) {
|
||||
SensorUtil.getRotationMatrixWithoutMagneticSensorData(rotationMatrix, accelerometerReading);
|
||||
}
|
||||
SensorManager.getOrientation(rotationMatrix, orientationAngles);
|
||||
|
||||
float pitch = orientationAngles[1];
|
||||
float roll = orientationAngles[2];
|
||||
float mag = (float) Math.sqrt(Math.pow(pitch, 2) + Math.pow(roll, 2));
|
||||
|
||||
if (mag > MAGNITUDE_MAXIMUM || mag < MAGNITUDE_MINIMUM) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (pitch > LANDSCAPE_PITCH_MINIMUM && pitch < LANDSCAPE_PITCH_MAXIMUM) {
|
||||
orientation.setValue(roll > 0 ? Orientation.LANDSCAPE_RIGHT_EDGE : Orientation.LANDSCAPE_LEFT_EDGE);
|
||||
} else {
|
||||
orientation.setValue(Orientation.PORTRAIT_BOTTOM_EDGE);
|
||||
}
|
||||
}
|
||||
|
||||
private final class EventListener implements SensorEventListener {
|
||||
|
||||
@Override
|
||||
public void onSensorChanged(SensorEvent event) {
|
||||
if (event.sensor.getType() == Sensor.TYPE_ACCELEROMETER) {
|
||||
System.arraycopy(event.values, 0, accelerometerReading, 0, accelerometerReading.length);
|
||||
} else if (event.sensor.getType() == Sensor.TYPE_MAGNETIC_FIELD) {
|
||||
System.arraycopy(event.values, 0, magnetometerReading, 0, magnetometerReading.length);
|
||||
}
|
||||
|
||||
updateOrientationAngles();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onAccuracyChanged(Sensor sensor, int accuracy) {
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,29 +0,0 @@
|
||||
package org.thoughtcrime.securesms.components.sensors;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
|
||||
public enum Orientation {
|
||||
PORTRAIT_BOTTOM_EDGE(0),
|
||||
LANDSCAPE_LEFT_EDGE(90),
|
||||
LANDSCAPE_RIGHT_EDGE(270);
|
||||
|
||||
private final int degrees;
|
||||
|
||||
Orientation(int degrees) {
|
||||
this.degrees = degrees;
|
||||
}
|
||||
|
||||
public int getDegrees() {
|
||||
return degrees;
|
||||
}
|
||||
|
||||
public static @NonNull Orientation fromDegrees(int degrees) {
|
||||
for (Orientation orientation : Orientation.values()) {
|
||||
if (orientation.degrees == degrees) {
|
||||
return orientation;
|
||||
}
|
||||
}
|
||||
|
||||
return PORTRAIT_BOTTOM_EDGE;
|
||||
}
|
||||
}
|
||||
@@ -1,92 +0,0 @@
|
||||
package org.thoughtcrime.securesms.components.sensors;
|
||||
|
||||
public final class SensorUtil {
|
||||
|
||||
private SensorUtil() { }
|
||||
|
||||
public static void getRotationMatrixWithoutMagneticSensorData(float[] rotationMatrix, float[] accelerometerReading) {
|
||||
double gx, gy, gz;
|
||||
gx = accelerometerReading[0] / 9.81f;
|
||||
gy = accelerometerReading[1] / 9.81f;
|
||||
gz = accelerometerReading[2] / 9.81f;
|
||||
|
||||
float pitch = (float) -Math.atan(gy / Math.sqrt(gx * gx + gz * gz));
|
||||
float roll = (float) -Math.atan(gx / Math.sqrt(gy * gy + gz * gz));
|
||||
float azimuth = 0;
|
||||
|
||||
float[] fakeMagnetometerReading = { azimuth, pitch, roll };
|
||||
|
||||
System.arraycopy(getRotationMatrixForOrientation(fakeMagnetometerReading), 0, rotationMatrix, 0, rotationMatrix.length);
|
||||
}
|
||||
|
||||
private static float[] getRotationMatrixForOrientation(float[] o) {
|
||||
float[] xM = new float[9];
|
||||
float[] yM = new float[9];
|
||||
float[] zM = new float[9];
|
||||
|
||||
float sinX = (float) Math.sin(o[1]);
|
||||
float cosX = (float) Math.cos(o[1]);
|
||||
float sinY = (float) Math.sin(o[2]);
|
||||
float cosY = (float) Math.cos(o[2]);
|
||||
float sinZ = (float) Math.sin(o[0]);
|
||||
float cosZ = (float) Math.cos(o[0]);
|
||||
|
||||
xM[0] = 1.0f;
|
||||
xM[1] = 0.0f;
|
||||
xM[2] = 0.0f;
|
||||
|
||||
xM[3] = 0.0f;
|
||||
xM[4] = cosX;
|
||||
xM[5] = sinX;
|
||||
|
||||
xM[6] = 0.0f;
|
||||
xM[7] = -sinX;
|
||||
xM[8] = cosX;
|
||||
|
||||
yM[0] = cosY;
|
||||
yM[1] = 0.0f;
|
||||
yM[2] = sinY;
|
||||
|
||||
yM[3] = 0.0f;
|
||||
yM[4] = 1.0f;
|
||||
yM[5] = 0.0f;
|
||||
|
||||
yM[6] = -sinY;
|
||||
yM[7] = 0.0f;
|
||||
yM[8] = cosY;
|
||||
|
||||
zM[0] = cosZ;
|
||||
zM[1] = sinZ;
|
||||
zM[2] = 0.0f;
|
||||
|
||||
zM[3] = -sinZ;
|
||||
zM[4] = cosZ;
|
||||
zM[5] = 0.0f;
|
||||
|
||||
zM[6] = 0.0f;
|
||||
zM[7] = 0.0f;
|
||||
zM[8] = 1.0f;
|
||||
|
||||
float[] resultMatrix = matrixMultiplication(xM, yM);
|
||||
resultMatrix = matrixMultiplication(zM, resultMatrix);
|
||||
return resultMatrix;
|
||||
}
|
||||
|
||||
private static float[] matrixMultiplication(float[] A, float[] B) {
|
||||
float[] result = new float[9];
|
||||
|
||||
result[0] = A[0] * B[0] + A[1] * B[3] + A[2] * B[6];
|
||||
result[1] = A[0] * B[1] + A[1] * B[4] + A[2] * B[7];
|
||||
result[2] = A[0] * B[2] + A[1] * B[5] + A[2] * B[8];
|
||||
|
||||
result[3] = A[3] * B[0] + A[4] * B[3] + A[5] * B[6];
|
||||
result[4] = A[3] * B[1] + A[4] * B[4] + A[5] * B[7];
|
||||
result[5] = A[3] * B[2] + A[4] * B[5] + A[5] * B[8];
|
||||
|
||||
result[6] = A[6] * B[0] + A[7] * B[3] + A[8] * B[6];
|
||||
result[7] = A[6] * B[1] + A[7] * B[4] + A[8] * B[7];
|
||||
result[8] = A[6] * B[2] + A[7] * B[5] + A[8] * B[8];
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
@@ -9,12 +9,6 @@ import org.thoughtcrime.securesms.util.MappingAdapter;
|
||||
* Reusable adapter for generic settings list.
|
||||
*/
|
||||
public class BaseSettingsAdapter extends MappingAdapter {
|
||||
|
||||
public BaseSettingsAdapter() {
|
||||
registerFactory(SettingHeader.Item.class, SettingHeader.ViewHolder::new, R.layout.base_settings_header_item);
|
||||
registerFactory(SettingProgress.Item.class, SettingProgress.ViewHolder::new, R.layout.base_settings_progress_item);
|
||||
}
|
||||
|
||||
public void configureSingleSelect(@NonNull SingleSelectSetting.SingleSelectSelectionChangedListener selectionChangedListener) {
|
||||
registerFactory(SingleSelectSetting.Item.class,
|
||||
new LayoutFactory<>(v -> new SingleSelectSetting.ViewHolder(v, selectionChangedListener), R.layout.single_select_item));
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
package org.thoughtcrime.securesms.components.settings;
|
||||
|
||||
import android.view.View;
|
||||
import android.widget.RadioButton;
|
||||
import android.widget.TextView;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
@@ -18,11 +20,13 @@ import java.util.Objects;
|
||||
public class CustomizableSingleSelectSetting {
|
||||
|
||||
public interface CustomizableSingleSelectionListener extends SingleSelectSetting.SingleSelectSelectionChangedListener {
|
||||
void onCustomizeClicked(@Nullable Item item);
|
||||
void onCustomizeClicked(@NonNull Item item);
|
||||
}
|
||||
|
||||
public static class ViewHolder extends MappingViewHolder<Item> {
|
||||
private final TextView summaryText;
|
||||
private final View customize;
|
||||
private final RadioButton radio;
|
||||
private final SingleSelectSetting.ViewHolder delegate;
|
||||
private final Group customizeGroup;
|
||||
private final CustomizableSingleSelectionListener selectionListener;
|
||||
@@ -31,34 +35,50 @@ public class CustomizableSingleSelectSetting {
|
||||
super(itemView);
|
||||
this.selectionListener = selectionListener;
|
||||
|
||||
radio = findViewById(R.id.customizable_single_select_radio);
|
||||
summaryText = findViewById(R.id.customizable_single_select_summary);
|
||||
customize = findViewById(R.id.customizable_single_select_customize);
|
||||
customizeGroup = findViewById(R.id.customizable_single_select_customize_group);
|
||||
|
||||
delegate = new SingleSelectSetting.ViewHolder(itemView, selectionListener);
|
||||
delegate = new SingleSelectSetting.ViewHolder(itemView, selectionListener) {
|
||||
@Override
|
||||
protected void setChecked(boolean checked) {
|
||||
radio.setChecked(checked);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@Override
|
||||
public void bind(@NonNull Item model) {
|
||||
delegate.bind(model.singleSelectItem);
|
||||
customizeGroup.setVisibility(model.singleSelectItem.isSelected() ? View.VISIBLE : View.GONE);
|
||||
customizeGroup.setVisibility(radio.isChecked() ? View.VISIBLE : View.GONE);
|
||||
customize.setOnClickListener(v -> selectionListener.onCustomizeClicked(model));
|
||||
if (model.getCustomValue() != null) {
|
||||
summaryText.setText(model.getSummaryText());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static class Item implements MappingModel<Item> {
|
||||
private final SingleSelectSetting.Item singleSelectItem;
|
||||
private final Object customValue;
|
||||
private SingleSelectSetting.Item singleSelectItem;
|
||||
private Object customValue;
|
||||
private String summaryText;
|
||||
|
||||
public <T> Item(@NonNull T item, @Nullable String text, boolean isSelected, @Nullable Object customValue, @Nullable String summaryText) {
|
||||
this.customValue = customValue;
|
||||
this.summaryText = summaryText;
|
||||
|
||||
singleSelectItem = new SingleSelectSetting.Item(item, text, summaryText, isSelected);
|
||||
singleSelectItem = new SingleSelectSetting.Item(item, text, isSelected);
|
||||
}
|
||||
|
||||
public @Nullable Object getCustomValue() {
|
||||
return customValue;
|
||||
}
|
||||
|
||||
public @Nullable String getSummaryText() {
|
||||
return summaryText;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean areItemsTheSame(@NonNull Item newItem) {
|
||||
return singleSelectItem.areItemsTheSame(newItem.singleSelectItem);
|
||||
@@ -66,7 +86,7 @@ public class CustomizableSingleSelectSetting {
|
||||
|
||||
@Override
|
||||
public boolean areContentsTheSame(@NonNull Item newItem) {
|
||||
return singleSelectItem.areContentsTheSame(newItem.singleSelectItem) && Objects.equals(customValue, newItem.customValue);
|
||||
return singleSelectItem.areContentsTheSame(newItem.singleSelectItem) && Objects.equals(customValue, newItem.customValue) && Objects.equals(summaryText, newItem.summaryText);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,63 +0,0 @@
|
||||
package org.thoughtcrime.securesms.components.settings;
|
||||
|
||||
import android.view.View;
|
||||
import android.widget.TextView;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.StringRes;
|
||||
|
||||
import org.thoughtcrime.securesms.R;
|
||||
import org.thoughtcrime.securesms.util.MappingModel;
|
||||
import org.thoughtcrime.securesms.util.MappingViewHolder;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* Provide a default header {@link MappingModel} and {@link MappingViewHolder} for settings screens.
|
||||
*/
|
||||
public final class SettingHeader {
|
||||
|
||||
public static final class ViewHolder extends MappingViewHolder<Item> {
|
||||
|
||||
private final TextView headerText;
|
||||
|
||||
public ViewHolder(@NonNull View itemView) {
|
||||
super(itemView);
|
||||
this.headerText = findViewById(R.id.base_settings_header_item_text);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void bind(@NonNull Item model) {
|
||||
if (model.text != null) {
|
||||
headerText.setText(model.text);
|
||||
} else {
|
||||
headerText.setText(model.textRes);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static final class Item implements MappingModel<Item> {
|
||||
private final int textRes;
|
||||
private final String text;
|
||||
|
||||
public Item(String text) {
|
||||
this.text = text;
|
||||
this.textRes = 0;
|
||||
}
|
||||
|
||||
public Item(@StringRes int textRes) {
|
||||
this.text = null;
|
||||
this.textRes = textRes;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean areItemsTheSame(@NonNull Item newItem) {
|
||||
return textRes == newItem.textRes && Objects.equals(text, newItem.text);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean areContentsTheSame(@NonNull Item newItem) {
|
||||
return areItemsTheSame(newItem);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,46 +0,0 @@
|
||||
package org.thoughtcrime.securesms.components.settings;
|
||||
|
||||
import android.view.View;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
|
||||
import org.thoughtcrime.securesms.util.MappingModel;
|
||||
import org.thoughtcrime.securesms.util.MappingViewHolder;
|
||||
|
||||
/**
|
||||
* Simple progress indicator that can be used multiple times (if provided with different {@link Item#id}s).
|
||||
*/
|
||||
public final class SettingProgress {
|
||||
|
||||
public static final class ViewHolder extends MappingViewHolder<SettingProgress.Item> {
|
||||
|
||||
public ViewHolder(@NonNull View itemView) {
|
||||
super(itemView);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void bind(@NonNull SettingProgress.Item model) { }
|
||||
}
|
||||
|
||||
public static final class Item implements MappingModel<SettingProgress.Item> {
|
||||
private final int id;
|
||||
|
||||
public Item() {
|
||||
this(0);
|
||||
}
|
||||
|
||||
public Item(int id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean areItemsTheSame(@NonNull SettingProgress.Item newItem) {
|
||||
return id == newItem.id;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean areContentsTheSame(@NonNull SettingProgress.Item newItem) {
|
||||
return areItemsTheSame(newItem);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,10 +1,7 @@
|
||||
package org.thoughtcrime.securesms.components.settings;
|
||||
|
||||
import android.text.TextUtils;
|
||||
import android.view.View;
|
||||
import android.widget.CheckedTextView;
|
||||
import android.widget.RadioButton;
|
||||
import android.widget.TextView;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
@@ -26,62 +23,46 @@ public class SingleSelectSetting {
|
||||
|
||||
public static class ViewHolder extends MappingViewHolder<Item> {
|
||||
|
||||
private final RadioButton radio;
|
||||
protected final CheckedTextView text;
|
||||
private final TextView summaryText;
|
||||
protected final SingleSelectSelectionChangedListener selectionChangedListener;
|
||||
|
||||
public ViewHolder(@NonNull View itemView, @NonNull SingleSelectSelectionChangedListener selectionChangedListener) {
|
||||
super(itemView);
|
||||
this.selectionChangedListener = selectionChangedListener;
|
||||
this.radio = findViewById(R.id.single_select_item_radio);
|
||||
this.text = findViewById(R.id.single_select_item_text);
|
||||
this.summaryText = findViewById(R.id.single_select_item_summary);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void bind(@NonNull Item model) {
|
||||
radio.setChecked(model.isSelected);
|
||||
text.setText(model.text);
|
||||
if (!TextUtils.isEmpty(model.summaryText)) {
|
||||
summaryText.setText(model.summaryText);
|
||||
summaryText.setVisibility(View.VISIBLE);
|
||||
} else {
|
||||
summaryText.setVisibility(View.GONE);
|
||||
}
|
||||
setChecked(model.isSelected);
|
||||
itemView.setOnClickListener(v -> selectionChangedListener.onSelectionChanged(model.item));
|
||||
}
|
||||
|
||||
protected void setChecked(boolean checked) {
|
||||
text.setChecked(checked);
|
||||
}
|
||||
}
|
||||
|
||||
public static class Item implements MappingModel<Item> {
|
||||
private final Object item;
|
||||
private final String text;
|
||||
private final String summaryText;
|
||||
private final Object item;
|
||||
private final boolean isSelected;
|
||||
|
||||
public <T> Item(@NonNull T item, @Nullable String text, @Nullable String summaryText, boolean isSelected) {
|
||||
this.item = item;
|
||||
this.summaryText = summaryText;
|
||||
this.text = text != null ? text : item.toString();
|
||||
this.isSelected = isSelected;
|
||||
public <T> Item(@NonNull T item, @Nullable String text, boolean isSelected) {
|
||||
this.item = item;
|
||||
this.text = text != null ? text : item.toString();
|
||||
this.isSelected = isSelected;
|
||||
}
|
||||
|
||||
public @NonNull String getText() {
|
||||
return text;
|
||||
}
|
||||
|
||||
public @NonNull Object getItem() {
|
||||
return item;
|
||||
}
|
||||
|
||||
public @Nullable String getText() {
|
||||
return text;
|
||||
}
|
||||
|
||||
public @Nullable String getSummaryText() {
|
||||
return summaryText;
|
||||
}
|
||||
|
||||
public boolean isSelected() {
|
||||
return isSelected;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean areItemsTheSame(@NonNull Item newItem) {
|
||||
return item.equals(newItem.item);
|
||||
@@ -89,9 +70,7 @@ public class SingleSelectSetting {
|
||||
|
||||
@Override
|
||||
public boolean areContentsTheSame(@NonNull Item newItem) {
|
||||
return Objects.equals(text, newItem.text) &&
|
||||
Objects.equals(summaryText, newItem.summaryText) &&
|
||||
isSelected == newItem.isSelected;
|
||||
return Objects.equals(text, newItem.text) && isSelected == newItem.isSelected;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user